说我有一个元组列表:
val ranges= List((1,4), (5,8), (9,10))
和数字列表
val nums = List(2,2,3,7,8,9)
我想从一个范围内的元组创建一个映射,以使num中给定数字落入该元组的区间的次数。
输出:
Map ((1,4) -> 3, (5,8) -> 2, (9,10) -> 1)
在Scala中解决它的最好方法是什么
我一直在尝试用于循环并保持计数器,但是没有达到要求。任何帮助将不胜感激。
最好的问候
答案 0 :(得分:5)
类似这样的东西:
val ranges = List((1, 4), (5, 8), (9, 10))
val nums = List(2, 2, 3, 7, 8, 9)
val occurences = ranges.map { case (l, r) => nums.count((l to r) contains _) }
val map = (ranges zip occurences).toMap
println(map) // Map((1,4) -> 3, (5,8) -> 2, (9,10) -> 1)
基本上,它首先计算出现次数[3,2,1]。从那里很容易构造地图。它计算出现次数的方式是:
nums
中包含多少个数字?编辑:不确定为什么这个答案会被否决,也许我以某种方式误解了这个问题。
答案 1 :(得分:3)
这是一种有效的单程解决方案:
ranges
.map(r => r -> nums.count(n => n >= r._1 && n <= r._2))
.toMap
这避免了创建数字列表然后在单独的步骤中将它们与范围压缩在一起的开销。
这是一个使用了更多Scala功能但有点花哨的版本:
(for {
r <- ranges
range = r._1 to r._2
} yield r -> nums.count(range.contains)
).toMap
效率也较低,因为contains
必须允许步长值的范围,因此更加复杂。
这是一个更加高效的版本,避免了任何临时数据结构:
val result: Map[(Int, Int), Int] =
ranges.map(r => r -> nums.count(n => n >= r._1 && n <= r._2))(collection.breakOut)
如果您对此不熟悉,请参阅此explanation of breakOut
。使用breakOut
意味着map
调用将直接构建Map
而不是创建必须使用{{1}转换为List
的{{1}} }。