【发布时间】:2012-04-17 01:12:54
【问题描述】:
我真的很喜欢函数式编程概念,但我现在在两个不同的场合都被同一个问题所困扰,当映射到一个恰好是 Set 的集合时(即自动删除重复项)。问题是在转换这样一个集合的元素之后,输出容器也是一个集合,因此会删除 transformed 输出的任何重复项。
一个非常简短的 REPL 会话来说明这个问题:
scala> case class Person(name: String, age: Int)
defined class Person
scala> val students = Set(Person("Alice", 18), Person("Bob", 18), Person("Charles", 19))
students: scala.collection.immutable.Set[Person] = Set(Person(Alice,18), Person(Bob,18), Person(Charles,19))
scala> val totalAge = (students map (_.age)).sum
totalAge: Int = 37
我当然希望总年龄为 18 + 18 + 19 = 55,但是因为 学生 存储在 Set 中,所以他们的年龄 在映射之后,因此18s 之一在年龄相加之前就消失了。
在实际代码中,这通常更隐蔽且更难发现,特别是如果您编写的实用程序代码仅采用 Traversable 和/或使用声明为返回 Traversable 的方法的输出(实现这恰好是一个集合)。在我看来,这些情况几乎不可能可靠地发现,除非/除非它们表现为错误。
那么,是否有任何最佳做法可以减少我遇到此问题的风险?将map-ping 考虑为在概念上将每个元素转换到位,而不是将转换后的元素依次添加到一些新集合中,我是否错了?如果我想保留这个心智模型,我应该在映射之前调用.toStream吗?
任何提示/建议将不胜感激。
更新:到目前为止,大多数答案都集中在将重复项包含在总和中的机制上。我对在一般情况下编写代码时所涉及的实践更感兴趣 - 在调用 map 之前,您是否已经训练自己总是在每个集合上调用 toList?在调用方法之前,您是否会仔细检查应用程序中所有集合的具体类?等等。
修复已被确定为问题的问题微不足道 - 最困难的部分是从一开始就防止这些错误蔓延。
【问题讨论】:
-
+1,很好的例子。作为一个集合离开显然会带来令人惊讶的结果,所以你“必须”做一些事情,创建一个新的集合,或其他方式来确保你所见即所得
-
完全复制:stackoverflow.com/questions/7040806/…。虽然这里的标题选择得更好。
-
感谢您的指点,@ziggy。我确实尝试过先搜索现有的问题,但没有提出任何问题(很难得出明确的描述)。
标签: scala collections functional-programming