当将`map`应用于`Set`时,你有时希望结果不是一组但忽略了这一点

zig*_*tar 8 scala

或者如何在映射时避免意外删除重复项Set

这是我经常犯的错误.看下面的代码:

def countSubelements[A](sl: Set[List[A]]): Int = sl.map(_.size).sum
Run Code Online (Sandbox Code Playgroud)

该函数应计算所有包含列表的累计大小.问题是在将列表映射到它们的长度之后,结果仍然是a,Set并且所有大小为1的列表都减少为单个代表.

这只是我有这个问题吗?我能做些什么来防止这种情况发生?我想我很想有两种方法mapToSet,并mapToSeqSet.但是没有办法强制执行此操作,有时您不会在本地注意到您正在使用Set.

也许你甚至有可能Seq在另一个类中编写代码以及某些更改并且底层对象变成了Set

也许是最好的做法,不要让这种情况出现?

远程编辑破坏了我的代码

想象一下以下情况:

val totalEdges = graph.nodes.map(_.getEdges).map(_.size).sum / 2
Run Code Online (Sandbox Code Playgroud)

Node从图形中获取对象的集合,使用它们来获取它们的相邻边缘并对它们求和.如果graph.nodes返回a,则有效Seq.

如果某人决定将Graph其节点作为一个返回,它就会中断Set; 没有这个代码看起来可疑(至少不是我,你认为每个集合可能最终成为一个Set?)而不触及它.

Lan*_*dei 1

解决方法:

def countSubelements[A](sl: Set[List[A]]): Int = sl.toSeq.map(_.size).sum

def countSubelements[A](sl: Set[List[A]]): Int = sl.foldLeft(0)(_ + _.size)
Run Code Online (Sandbox Code Playgroud)

  • @ziggystar - 为了完全不犯错误,请使用折叠而不是映射/总和。如果您大量使用集合,您可以将其作为“最佳实践”(即对所有集合执行此操作,因此无论您使用哪一个集合都没有关系)。考虑到您不希望映射集实际上被映射为一个集合,您实际上_意思_是折叠,而不是映射/总和。 (5认同)
  • 我不同意。sum 已经作为折叠实现 - 它是 Fold(0)(_ + _)。您确实可以编写上述建议中的任何一个,但我认为更好的最佳实践就是“始终使用 toSeq”,因为上面的第一行更自然。第二行是不对称的,因此不太优雅,甚至在底层集合并行的上下文中效率可能较低 - 在这种上下文中,fold 可以比 FoldLeft/foldRight 更好地优化。 (2认同)