简体   繁体   English

Scala遍历列表

[英]Scala iterate over list

How can I convert List(1,2,30,13,4) to List(1,2,3,4) without using mutable collection? 如何在不使用可变集合的情况下将List(1,2,30,13,4)转换为List(1,2,3,4)

30 is a kind of escape number; 30是一种转义号码; if found, it should be removed, and next number should be decreased by 10. 如果找到,应将其删除,下一个数字应减少10。

You should probably review your code/use case because this kinda smells, anyway: 无论如何,您可能应该检查您的代码/用例,因为有点类似:

List(1,2,30,13,4).foldLeft((List.empty[Int], false)) {
  case ((accumulator, wasFound), next) =>
    if(wasFound) (accumulator :+ (next - 10), false)
    else if(next == 30) (accumulator, true)
    else (accumulator :+ next, false)
}._1

Basically you can keep a boolean and an accumulator and use it to remember if a 30 was found or not and take the appropriate action in case it was. 基本上,您可以保留一个布尔值和一个累加器,并使用它来记住是否找到了30,并采取适当的措施以防万一。

Note that this won't help you if you have something like List(1,3,30,40) , the output would be List(1,3,30) , you should make clear if this case is acceptable or not, if not I would use a recursive solution which will allow to iterate an element twice in case it's a 30: 请注意,如果您有类似List(1,3,30,40)的输出,这将对您没有帮助,输出将是List(1,3,30) ,您应该弄清楚这种情况是否可以接受,如果不,我将使用一个递归解决方案,该解决方案允许在元素为30的情况下对元素进行两次迭代:

scala> def loop(list: List[Int], acc: List[Int], wasFound: Boolean, toRemove: Int): List[Int] = list match {
 |     case h :: t =>
 |       if(wasFound) loop((h - 10) :: t, acc, false, toRemove)
 |       else if(h == toRemove) loop(t, acc, true, toRemove)
 |       else loop(t, acc :+ h, false, toRemove)
 |     case Nil =>
 |       acc
 |   }
loop: (list: List[Int], acc: List[Int], wasFound: Boolean, toRemove: Int)List[Int]

scala> loop(List(1,2,30,13,4), List(), false, 30)
res1: List[Int] = List(1, 2, 3, 4)

scala> loop(List(1,2,30,40, 13,4), List(), false, 30)
res2: List[Int] = List(1, 2, 3, 4)

The logic is very similar, the only difference is you iterate twice the one found after the 30, so that if it's another 30 it gets removed and the next decreased. 逻辑非常相似,唯一的不同是您对30之后的那个进行了两次迭代,因此,如果它又是30,则将其删除并减少下一个。

Zip previous item to each item, and then decide if and what to return using collect and a partial function: 将上一个项目压缩到每个项目,然后使用collect和部分函数确定是否返回什么:

l.zip(l.head :: l).collect {
  case (v, 30) if v != 30 => v - 10  // only previous is 30 - decrease 10
  case (v, prev) if v != 30 => v     // none of them is 30 - just return value
  // skipping (filtering out) case where v == 30
}

For example: 例如:

  • for val l = List(1,2,30,13,4,30,15,6) , this would return List(1,2,3,4,5,6) 对于val l = List(1,2,30,13,4,30,15,6) ,这将返回List(1,2,3,4,5,6)
  • for val l = List(1,3,30,40) , returns List(1,3,30) 对于val l = List(1,3,30,40) ,返回List(1,3,30)
  • for val l = List(30,11,2) , returns List(1,2) 对于val l = List(30,11,2) ,返回List(1,2)

Along lines of @Victor comment, and generalizing: 遵循@Victor注释并概括:

def escapeAdjust[A](xs: List[A], p: A => Boolean, f: A => A): List[A] = {
  @tailrec
  def loop(ys: List[A], p: A => Boolean, f: A => A, acc: List[A]): List[A] = ys match {
    case Nil => acc
    case h :: Nil => if (p(h)) acc else h :: acc
    case h :: next :: rest => if (p(h)) loop(f(next) :: rest, p, f, acc)
                              else loop(next :: rest, p, f, h :: acc)
  }
  loop(xs, p, f, List[A]()).reverse
}

usage: 用法:

val p = (x: Int) => x == 30
val f = (y: Int) => y - 10

escapeAdjust(List[Int](1,2,30,13,4), p, f)
res12: List[Int] = List(1, 2, 3, 4)

escapeAdjust(List(1,2,30,13,4,30,15,6), p, f)
res13: List[Int] = List(1, 2, 3, 4, 5, 6)

escapeAdjust(List(1,3,30,40), p, f)
res14: List[Int] = List(1, 3)

escapeAdjust(List(30,11,2), p, f)
res15: List[Int] = List(1, 2)

escapeAdjust(List(1,3,30,40, 5), p, f)
res16: List[Int] = List(1, 3, -5)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM