Scala:从元组列表构建映射,但如果存在矛盾的条目则失败
我想这可能是一个常见的操作。所以也许它在 API 内部,但我找不到它。如果没有的话,我也对高效功能/简单的解决方案感兴趣。
给定一个元组序列 ("a" -> 1, "b" ->2, "c" -> 3)
我想将其转换为地图。使用 TraversableOnce.toMap
可以轻松实现这一点。但如果生成的映射“包含矛盾”,即分配给同一键的不同值,我希望此构造失败。就像序列 ("a" -> 1, "a" -> 2)
一样。但允许重复。
目前我有这个(非常必要的)代码:
def buildMap[A,B](in: TraversableOnce[(A,B)]): Option[Map[A,B]] = {
val map = new HashMap[A,B]
val it = in.toIterator
var fail = false
while(it.hasNext){
val next = it.next()
val old = map.put(next._1, next._2)
fail = old.isDefined && old.get != next._2
}
if(fail) None else Some(map.toMap)
}
附带问题
最终的toMap
真的有必要吗?省略它时出现类型错误,但我认为它应该有效。 toMap 的实现构造了一个我想避免的新地图。
I think this might be a common operation. So maybe it's inside the API but I can't find it. Also I'm interested in an efficient functional/simple solution if not.
Given a sequence of tuples ("a" -> 1, "b" ->2, "c" -> 3)
I want to turn it into a map. That's easy using TraversableOnce.toMap
. But I want to fail this construction if the resulting map "would contain a contradiction", i.e. different values assigned to the same key. Like in the sequence ("a" -> 1, "a" -> 2)
. But duplicates shall be allowed.
Currently I have this (very imperative) code:
def buildMap[A,B](in: TraversableOnce[(A,B)]): Option[Map[A,B]] = {
val map = new HashMap[A,B]
val it = in.toIterator
var fail = false
while(it.hasNext){
val next = it.next()
val old = map.put(next._1, next._2)
fail = old.isDefined && old.get != next._2
}
if(fail) None else Some(map.toMap)
}
Side Question
Is the final toMap
really necessary? I get a type error when omitting it, but I think it should work. The implementation of toMap
constructs a new map which I want to avoid.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
与往常一样,在使用
Seq[A]
时,性能方面的最佳解决方案取决于具体的集合类型。一个通用但不是很有效的解决方案是折叠
Option[Map[A,B]]
:如果您限制自己使用
List[A,B]
优化版本是:另外,使用可变映射的不太惯用的版本可以像这样实现:
As always when working with
Seq[A]
the optimal solution performance-wise depends on the concrete collection type.A general but not very efficient solution would be to fold over an
Option[Map[A,B]]
:If you restrict yourself to using
List[A,B]
s an optimized version would be:Additionally a less idiomatic version using mutable maps could be implemented like this:
这是一个缓慢失败的解决方案(如果创建整个地图然后丢弃它是可以的):
这是一个可变的快速失败解决方案(一旦检测到错误就立即退出):
这是一个不可变的快速失败解决方案:
编辑:这是一个使用
put
来提高速度的解决方案(希望如此):编辑:现在经过测试,它的输入速度(返回 true)比 Moritz 或我的直接解决方案快大约 2 倍。
Here is a fail-slowly solution (if creating the entire map and then discarding it is okay):
Here is a mutable fail-fast solution (bail out as soon as the error is detected):
And here's an immutable fail-fast solution:
Edit: and here's a solution using
put
for speed (hopefully):Edit: now tested, and it's ~2x as fast on input that works (returns true) than Moritz' or my straightforward solution.
Scala 2.9 即将到来,那么为什么不利用组合方法(受到 Moritz 答案的启发):
Scala 2.9 is near, so why not to take advantage of the combinations method (inspired by Moritz's answer):
您还可以按如下方式使用 gourpBy:
它的效率与上述解决方案具有竞争力。
事实上,如果您检查 gourpBy 实现,您会发现它与建议的一些解决方案非常相似。
You can also use gourpBy as follows:
It's efficiency is competitive to the above solutions.
In fact if you examine the gourpBy implementation you will see that it is very similar to some of the solutions suggested.