我有一个List [Int],也许像这样:
List(1,2,3,3,4,5,6,6,7,8,9)
偶尔会有重复(总是2次,而不是更多)。有dup时,我想将元素与函数合并在一起。因此,在这个简单的示例中,如果我的功能是将两个数字相加,我将得到:
List(1,2,6,4,5,12,7,8,9)
执行此操作的简洁方法是什么? List.map()一次只能查看/转换1个元素。
答案 0 :(得分:2)
您可以将.foldLeft
与新列表一起用作累加器(假设列表彼此相邻重复)
def mergeDuplicates(list: List[Int]): List[Int] = {
list.foldLeft(List.empty[Int]) {
case (l, elem) if l.lastOption.contains(elem) =>
l.dropRight(1) :+ (2 * elem)
case (l, elem) =>
l :+ elem
}
}
println(mergeDuplicates(List(1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9)))
// output List(1, 2, 6, 4, 5, 12, 7, 8, 9)
implicit class ListOps(list: List[Int]) {
def mergeDuplicates: List[Int] = {
list.foldLeft(List.empty[Int]) {
case (l, elem) if l.lastOption.contains(elem) =>
l.dropRight(1) :+ (2 * elem)
case (l, elem) =>
l :+ elem
}
}
}
val mergedList = List(1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9).mergeDuplicates
println(mergedList)
答案 1 :(得分:2)
从Scala 2.13
开始,您可以将List#unfold
与List#span
结合使用:
// val items = List(1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9)
List.unfold(items) {
case Nil => None
case rest => Some(rest.span(_ == rest.head))
}
.map(_.sum)
// List(1, 2, 6, 4, 5, 12, 7, 8, 9)
,甚至结合Scala 2.13
的{{3}}构建器:
List
.unfold(items)(rest => Option.unless(rest.isEmpty)(rest.span(_ == rest.head)))
.map(_.sum)
List(1, 2, 3, 3, 4, 5, 6, 6, 7, 8, 9)
初始化的,该列表要对其连续的重复项求和。span
使用该内部状态来查找标题的连续项:rest.span(_ == rest.head)
(例如,在List(3, 3, 4, 5, ...)
内部状态的第三次迭代期间,{{{ 1}})。(List(3, 3), List(5, 6, ...))
在每个迭代中期望一个元组的unfold
,其第一部分是要添加到要构建的列表中的新元素(例如,在第一次迭代中,Option
),其第二部分是内部状态的新值(List(1)
),该范围完全符合该要求。List(2, 3, 3, ...)
表示None
已经完成,并且迭代必须停止。unfold
用它们的总和替换分组的部分(List(List(1), ..., List(3, 3), ...)
)。当然,这也可以在展开的过程中实现,但要付出一些额外的样板。