列出其元素取决于先前的元素

时间:2020-06-11 09:56:16

标签: scala

假设我有一个递增整数的列表。如果两个连续数字的差小于阈值,那么我们将从0开始以相同的数字对其进行索引。否则,我们将索引增加1。

例如:对于列表(1,2,5,7,8,11,15,16,20)并且阈值= 3,输出将为:(0,0,1,1,1,1, 2、3、3、4)。

这是我的代码:

  val listToGroup = List(1,2,5,7,8,11,15,16,20)
  val diff_list = listToGroup.sliding(2,1).map{case List(i, j) => j-i}.toList

  val thres = 2

  var j=0
  val output_ = for(i <- diff_list.indices) yield {
    if (diff_list(i) > thres ) {
      j += 1
    }
    j
  }
  val output = List.concat(List(0), output_)

我是Scala的新手,我觉得列表没有得到有效使用。该代码如何进行改进?

2 个答案:

答案 0 :(得分:3)

您可以通过使用scanLeft来获得更惯用的代码来避免使用可变变量:

val output = diff_list.scanLeft(0) { (count, i) => 
  if (i > thres) count + 1
  else count
}

您的代码显示了一些在Scala中通常避免使用的构造,但在来自过程语言时却很常见,例如:for(i <- diff_list.indices) ... diff_list(i)可以用for(i <- diff_list)替换。

除此之外,我认为您的代码是有效的-无论如何,您都需要遍历列表,并在O(N)中进行操作。在这里,我不用担心效率,而不必担心样式和可读性。

我对整个代码在Scala中更自然的看法是:

val listToGroup = List(1,2,5,7,8,11,15,16,20)

val thres = 2

val output = listToGroup.zip(listToGroup.drop(1)).scanLeft(0) { case (count, (i, j)) => 
  if (j - i > thres) count + 1
  else count
}

我对您代码的调整:

  • 我使用scanLeft进行结果收集构建
  • 相对于x.zip(x.drop(1)),我更喜欢x.sliding(2, 1)(构造元组似乎比构造集合更有效)。您也可以使用x.zip(x.tail),但这不能处理空的x
  • 我避免了临时结果diff_list

答案 1 :(得分:2)

val listToGroup = List(1, 2, 5, 7, 8, 11, 15, 16, 20)

val thres = 2

listToGroup
  .sliding(2)
  .scanLeft(0)((a, b) => { if (b.tail.head - b.head > thres) a + 1 else a })
  .toList
  .tail

您不需要使用可变变量,可以使用scanLeft实现相同的功能。