Scala - 从List中获取带有扭曲的唯一值

fmp*_*ard 4 scala scala-collections

我有一个这样的列表:

val l= List(("Agent", "PASS"), ("Agent", "FAIL"), ("Agent 1", "FAIL"), ("Agent", "PASS"), ("Agent 2", "PASS") )
Run Code Online (Sandbox Code Playgroud)

我需要得到一个这样的列表:

val filteredList= List(("Agent", "FAIL"), ("Agent 1", "FAIL"), ("Agent 2", "PASS") )
Run Code Online (Sandbox Code Playgroud)

发生了什么?

("Agent", "PASS"), ("Agent", "FAIL")
Run Code Online (Sandbox Code Playgroud)

("Agent", "FAIL")
Run Code Online (Sandbox Code Playgroud)

(因为如果至少有一次失败,我需要保留该条目)

代理1和代理2的条目保持不变,因为每个条目只有一个条目.

我找到的最接近的答案是 如何在Scala中找到列表中的唯一项目, 但我无法告诉如何使用FAIL保留条目.

我希望这个问题很清楚,如果没有,我可以给你一个更好的例子.

谢谢

Kev*_*ght 9

前言

在我看来,状态可以被视为具有优先级,并且如果给出一系列(agent,status)对,则任务是仅为每个代理选择最高优先级状态.不幸的是,状态并没有强烈地键入如此定义的显式排序,但是......因为它只是一个只有两个值的字符串,所以我们可以安全地使用字符串排序,因为它与优先级具有1:1的对应关系.

我的答案都利用了两个有用的事实:

  1. 在自然字符串排序中"FAIL" < "PASS",所以:

    List("PASS", "FAIL", "PASS").sorted.head = "FAIL"
    
    Run Code Online (Sandbox Code Playgroud)
  2. 对于两个元(x,a)(x,b), (x,a) > (x, b)如果(a > b)

更新回复

val solution = l.sorted.reverse.toMap
Run Code Online (Sandbox Code Playgroud)

当通过该方法将a转换Seq[(A,B)]为a 时,原始元组序列中的每个"键"只能出现在生成的Map中一次.碰巧,转换使用最后一次这样的事件.Map[A,B].toMap

l.sorted.reverse = List(
  (Agent 2,PASS),  // <-- Last "Agent 2"
  (Agent 1,FAIL),  // <-- Last "Agent 1"
  (Agent,PASS),
  (Agent,PASS),
  (Agent,FAIL))    // <-- Last "Agent"

l.sorted.reverse.toMap = Map(
  Agent 2 -> PASS,
  Agent 1 -> FAIL,
  Agent -> FAIL)
Run Code Online (Sandbox Code Playgroud)

原始回复

从答案开始......

val oldSolution = (l groupBy (_._1)) mapValues {_.sorted.head._2}
Run Code Online (Sandbox Code Playgroud)

......然后展示我的工作:)

//group
l groupBy (_._1) = Map(
  Agent 2 -> List((Agent 2,PASS)),
  Agent 1 -> List((Agent 1,FAIL)),
  Agent -> List((Agent,PASS), (Agent,FAIL), (Agent,PASS))
)

//extract values
(l groupBy (_._1)) mapValues {_.map(_._2)} = Map(
  Agent 2 -> List(PASS),
  Agent 1 -> List(FAIL),
  Agent -> List(PASS, FAIL, PASS))

//sort
(l groupBy (_._1)) mapValues {_.map(_._2).sorted} = Map(
  Agent 2 -> List(PASS),
  Agent 1 -> List(FAIL),
  Agent -> List(FAIL, PASS, PASS))

//head
(l groupBy (_._1)) mapValues {_.map(_._2).sorted.head} = Map(
  Agent 2 -> PASS,
  Agent 1 -> FAIL,
  Agent -> FAIL)
Run Code Online (Sandbox Code Playgroud)

但是,您可以直接对agent -> status对进行排序,而无需先提取_2:

//group & sort
(l groupBy (_._1)) mapValues {_.sorted} = Map(
  Agent 2 -> List((Agent 2,PASS)),
  Agent 1 -> List((Agent 1,FAIL)),
  Agent -> List((Agent,FAIL), (Agent,PASS), (Agent,PASS)))

//extract values
(l groupBy (_._1)) mapValues {_.sorted.head._2} = Map(
  Agent 2 -> PASS,
  Agent 1 -> FAIL,
  Agent -> FAIL)
Run Code Online (Sandbox Code Playgroud)

在任何一种情况下,如果您愿意,可以随意转换回对应列表:

l.sorted.reverse.toMap.toList = List(
  (Agent 2, PASS),
  (Agent 1, FAIL),
  (Agent, FAIL))
Run Code Online (Sandbox Code Playgroud)

  • `l.sorted.reverse.toMap`很漂亮,但我确信我永远不会记得为什么它将来有用.;-) (3认同)

Syn*_*sso 6

这是你想要的吗?

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))
Run Code Online (Sandbox Code Playgroud)

或者这是一个更短,更模糊的解决方案:

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))
Run Code Online (Sandbox Code Playgroud)

  • 假设第二个String值限制为"PASS"或"FAIL",则类型应为布尔值.这对简化解决方案大有帮助. (2认同)