scalascala-collections

Get unique values from a List by a property, keeping certain values on duplicates


I have a list like this:

val l= List(("Agent", "PASS"), ("Agent", "FAIL"), ("Agent 1", "FAIL"), ("Agent", "PASS"), ("Agent 2", "PASS") )

I need to end up with a list like this:

val filteredList= List(("Agent", "FAIL"), ("Agent 1", "FAIL"), ("Agent 2", "PASS") )

This:

("Agent", "PASS"), ("Agent", "FAIL")

becomes:

("Agent", "FAIL")

because if there is at least one "FAIL", I need to keep that entry.

The entries for "Agent 1" and "Agent 2" stay the same because there are just one entry for each.

The closest answer I found is How in Scala to find unique items in List, but I cannot tell how to keep the entries with "FAIL".


Solution

  • Is this what you want?

    jem@Respect:~$ scala
    Welcome to Scala version 2.8.0.final (Java HotSpot(TM) Client VM, Java 1.6.0_21).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala> val l= List(("Agent", "PASS"), ("Agent", "FAIL"), ("Agent 1", "FAIL"), ("Agent", "PASS"), ("Agent 2", "PASS") )
    l: List[(java.lang.String, java.lang.String)] = List((Agent,PASS), (Agent,FAIL), (Agent 1,FAIL), (Agent,PASS), (Agent 2,PASS))
    
    scala> l.foldLeft(Map.empty[String, String]){(map,next) =>
         |   val (agent, result) = next
         |   if ("FAIL" == result) map.updated(agent, result)
         |   else {           
         |     val maybeExistingResult = map.get(agent)
         |     if (maybeExistingResult.map(_ == "FAIL").getOrElse(false)) map
         |     else map.updated(agent, result)
         |   }
         | }
    res0: scala.collection.immutable.Map[String,String] = Map((Agent,FAIL), (Agent 1,FAIL), (Agent 2,PASS))
    
    scala> res0.toList
    res1: List[(String, String)] = List((Agent 2,PASS), (Agent 1,FAIL), (Agent,FAIL))
    

    Or here is a shorter and more obscure solution:

    scala> l.groupBy(_._1).map(pair => (pair._1, pair._2.reduceLeft((a,b) => if ("FAIL" == a._2 || "FAIL" == b._2) (a._1, "FAIL") else a))).map(_._2).toList
    res2: List[(java.lang.String, java.lang.String)] = List((Agent 2,PASS), (Agent 1,FAIL), (Agent,FAIL))