我想在Scala中减去带有数字的列表中的两个连续元素。
例如:我有这个列表:
val sortedList = List(4,5,6)
我想有一个像diffList =(1, 1)
这样的输出列表,其中5-4 = 1
和6-5 = 1
。
我尝试了以下代码:
var sortedList = List[Int]()
var diffList = List[Int]()
for (i <- 0 to (sortedList.length - 1) ;j <- i + 1 to sortedList.length - 1)
{
val diff = (sortedList(j) - sortedList(i))
diffList = diffList :+ diff
}
我有以下diffList =(1, 2, 1)
的结果,但我想要diffList = (1,1)
。
这是因为for循环。它不会一次遍历两个变量(i和j)。
你不用可变性也不用命令式编程来解决这个问题,函数式编程帮你解决了。
def consecutiveDifferences(data: List[Int]): List[Int] =
if (data.isEmpty) List.empty
else data.lazyZip(data.tail).map {
case (x, y) => y - x
}
就像我常说的,Scaladoc是你的朋友。
(另外,作为一个建议,学习函数式编程的最好方法是禁止自己使用可变性)
您可以使用sliding
方法,根据文档:
/** Groups elements in fixed size blocks by passing a "sliding window" * over them (as opposed to partitioning them, as is done in `grouped`.) * * An empty collection returns an empty iterator, and a non-empty * collection containing fewer elements than the window size returns * an iterator that will produce the original collection as its only * element. * @see [[scala.collection.Iterator]], method `sliding` * * @param size the number of elements per group * @return An iterator producing ${coll}s of size `size`, except for a * non-empty collection with less than `size` elements, which * returns an iterator that produces the source collection itself * as its only element. * @example `List().sliding(2) = empty iterator` * @example `List(1).sliding(2) = Iterator(List(1))` * @example `List(1, 2).sliding(2) = Iterator(List(1, 2))` * @example `List(1, 2, 3).sliding(2) = Iterator(List(1, 2), List(2, 3))` */
然后,解决您的查询非常直接:
diffList = sortedList.sliding(2).collect {
case Seq(a, b) =>
b - a
}.toList
结果是List(1,1)
在Scastie上运行的代码。
for(i <- 0 until (sortedList.size - 1)) yield sortedList(i + 1) - sortedList(i)
生成Vector(1,1)
,toList
可以转换为list
这也可以通过以下函数实现:
val sortedList = List(4,5,7)
@tailrec
def findDiffs(xs: List[Int])(seed: List[Int]): List[Int] = {
if(xs.isEmpty || xs.size == 1) seed.reverse
else {
val currDiff = xs(1) - xs(0)
findDiffs(xs.tail)(currDiff :: seed)
}
}
val res = findDiffs(sortedList)(Nil)
println(res)
或者直接使用zip:
sortedList.drop(1) zip sortedList map { case (x,y) => x - y }
在列表上滑动(参见@Tomer Shetah的回答)提供了一个迭代器,这对于非常大的集合来说可能很方便,可以避免/减少处理中的中间结构的数量。另一种方法包括压缩列表,将列表本身移动一个(参见@Luis Miguel Mejía Suárez和@Zvi Mints的答案);在这种情况下,移动然后压缩的另一种方法是删除第一个元素,如
xs.drop(1) zip xs map {case(a,b) => b-a}
这可以通过去掉任意数字n
来推广,这样我们就可以减去第一个和n
-th元素,然后减去第二个和n+1
-th元素,以此类推。