How can I convert List(1,2,30,13,4)
to List(1,2,3,4)
without using mutable collection?
30 is a kind of escape number; if found, it should be removed, and next number should be decreased by 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.
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:
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.
Zip previous item to each item, and then decide if and what to return using collect
and a partial function:
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:
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,3,30,40)
, returns List(1,3,30)
val l = List(30,11,2)
, returns List(1,2)
Along lines of @Victor comment, and generalizing:
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)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.