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保留条目.
我希望这个问题很清楚,如果没有,我可以给你一个更好的例子.
谢谢
前言
在我看来,状态可以被视为具有优先级,并且如果给出一系列(agent,status)对,则任务是仅为每个代理选择最高优先级状态.不幸的是,状态并没有强烈地键入如此定义的显式排序,但是......因为它只是一个只有两个值的字符串,所以我们可以安全地使用字符串排序,因为它与优先级具有1:1的对应关系.
我的答案都利用了两个有用的事实:
在自然字符串排序中"FAIL" < "PASS",所以:
List("PASS", "FAIL", "PASS").sorted.head = "FAIL"
Run Code Online (Sandbox Code Playgroud)对于两个元(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)
这是你想要的吗?
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)