Reputation: 91
I have a list which may contain certain consecutive identical elements.I want to replace many consecutive identical elements with one. How to do it in scala
Lets say my list is
List(5, 7, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
I want output list as
List(5, 7, 2, 3, 5, 3, 2)
Upvotes: 9
Views: 3327
Reputation: 386
val myList = List(5, 7, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
myList.foldRight[List[Int]](Nil) { case (x, xs) =>
if (xs.isEmpty || xs.head != x) x :: xs else xs }
// res: List[Int] = List(5, 7, 2, 3, 5, 3, 2)
Upvotes: 4
Reputation: 41769
Yet another variant
val is = List(5, 7,2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
val ps = is.head::((is zip is.tail) collect { case (a,b) if a != b => b })
//> ps : List[Int] = List(5, 7, 2, 3, 5, 3, 2)
(the is zip is.tail
is doing something similar to .sliding(2)
)
Upvotes: 0
Reputation: 159
import scala.collection.mutable.ListBuffer
object HelloWorld {
def main(args:Array[String]) {
val lst=List(5, 7, 2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
val lstBf=ListBuffer[Int](lst.head)
for(i<-0 to lst.length-2){
if(lst(i)!=lst(i+1)){
lstBf+=lst(i+1)
}
}
println(lstBf.toList)
}
}
Upvotes: 1
Reputation: 44957
(answer moved from this duplicate)
Here is a variant that is
Code:
def compress[A](xs: List[A]): List[A] = {
@annotation.tailrec
def rec(rest: List[A], stack: List[A]): List[A] = {
(rest, stack) match {
case (Nil, s) => s
case (h :: t, Nil) => rec(t, List(h))
case (h :: t, a :: b) =>
if (h == a) rec(t, stack)
else rec(t, h :: stack)
}
}
rec(xs, Nil).reverse
}
Example
println(compress(List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)))
produces the following output:
List('a, 'b, 'c, 'a, 'd, 'e)
Upvotes: 2
Reputation: 1389
Try this,
val y = list.sliding(2).toList
val x =y.filter(x=> (x.head != x.tail.head)).map(_.head) :+ (y.reverse.filter(x=> x.head !=x.tail.head)).head.tail.head
Upvotes: 0
Reputation: 520
val l = List(5, 7,2, 3, 3, 3, 5, 5, 3, 3, 2, 2, 2)
def f(l: List[Int]): List[Int] = l match {
case Nil => Nil
case x :: y :: tail if x == y => f(y::tail)
case x :: tail => x :: f(tail)
}
println(f(l)) //List(5, 7, 2, 3, 5, 3, 2)
Of course you can make it tail recursive
Upvotes: 1
Reputation: 52691
It can be done pretty cleanly using sliding
:
myList.head :: myList.sliding(2).collect { case Seq(a,b) if a != b => b }.toList
It looks at all the pairs, and for every non-matching pair (a,b)
, it gives you back b
. But then it has to stick the original a
on the front of the list.
Upvotes: 7
Reputation: 6069
I'm sure there is a better way.
list.tail.foldLeft(List[Int](list.head))((prev, next) => {
if (prev.last != next) prev +: next
else prev
})
foldLeft
takes a parameter (in the first application) and goes from left to right through your list, applying prev
and next
to the two parameter function it is given, where prev
is the result of the function so far and next
is the next element in your list.
list.zipWithIndex.filter(l => (l._2 == 0) || (l._1 != list(l._2-1))).map(_._1)
In general, list.zip(otherList)
returns a list of tuples of corresponding elements. For example List(1,2,3).zip(List(4,5,6))
will result in List((1,4), (2,5), (3,6))
. zipWithIndex
is a specific function which attaches each list element with its index, resulting in a list where each element is of the form (original_list_element, index)
.
list.filter(function_returning_boolean)
returns a list with only the elements that returned true
for function_returning_boolean
. The function I gave simply checks if this element is equal to the previous in the original list (or the index is 0).
The last part, .map(_._1)
just removes the indices.
Upvotes: 4