Split a list into multiple lists with String and Integers - scala

I have an input like below:
List("aabc", 3, 1, 2, 1, "vwxyz", 2, 3, 4, "sdsafw", 4, 1, 2, 22, 4)
And I would like to split it as follows:
List(List(“aabc”, 3, 1, 2, 1), List(“vwxyz”, 2, 3, 4), List(“sdsafw”, 4, 1, 2, 22, 4))
or
List(List(“aabc”, 1, 2, 1), List(“vwxyz”, 3, 4), List(“sdsafw”, 1, 2, 22, 4))
(The number right after each “String” actually indicates how many integers come after itself. And if it can be done nicely, I would like to remove it at this point.)
Would you tell me how I can do this?

If you have a List as
val list = List("aabc", 3, 1, 2, 1, "vwxyz", 2, 3, 4, "sdsafw", 4, 1, 2, 22, 4)
Then you can write a recursive function as
def splitList(list: List[Any], tempList: List[Any], listBuffer: ListBuffer[List[Any]]): ListBuffer[List[Any]] = list match {
case x :: y => if(tempList.isEmpty){
splitList(y, List(x), listBuffer)
}
else {
splitList(y.drop(x.asInstanceOf[Int]), List.empty, listBuffer += tempList ++ List(x) ++ y.take(x.asInstanceOf[Int]))
}
case Nil => listBuffer
}
Calling this function
println(splitList(list, List.empty, ListBuffer.empty[List[Any]]))
would give you your desired output
ListBuffer(List(aabc, 3, 1, 2, 1), List(vwxyz, 2, 3, 4), List(sdsafw, 4, 1, 2, 22, 4))
You can manipulate the desired output with ListBuffer or Array or List according to your need.
Yet Another form of your solution can be using following recursive function.
def splitList(list: List[Any], tempList: List[Any], listBuffer: ListBuffer[List[Any]]): ListBuffer[List[Any]] = list match {
case x :: y => if (x.isInstanceOf[String]) {
if(!tempList.isEmpty){
splitList(y, List(x), listBuffer += tempList)
}
else {
splitList(y, List(x), listBuffer)
}
}else splitList(y, tempList ++ List(x), listBuffer)
case Nil => listBuffer += tempList
}

Related

Finding all slices delimited by two elements in Scala `List`

In Scala, what would be the right way of selecting elements of a list based on the position of two elements? Suppose I have the list below and I would like to select all the elements between 2 and 7, including them (note: not greater than/smaller than, but the elements that come after 2 and before 7 in the list):
scala> val l = List(1, 14, 2, 17, 35, 9, 12, 7, 9, 40)
l: List[Int] = List(1, 14, 2, 17, 35, 9, 12, 7, 9, 40)
scala> def someMethod(l: List[Int], from: Int, to: Int) : List[Int] = {
| // some code here
| }
someMethod: (l: List[Int], from: Int, to: Int)List[Int]
scala> someMethod(l, 2, 7)
res0: List[Int] = List(2, 17, 35, 9, 12, 7)
Expected output:
For lists that don't contain 2 and/or 7: an empty list
Input: (1, 2, 2, 2, 3, 4, 7, 8); Output: (2, 2, 2, 3, 4, 7)
Input: (1, 2, 3, 4, 7, 7, 7, 8); Output: (2, 3, 4, 7)
Input: (1, 2, 3, 4, 7, 1, 2, 3, 5, 7, 8); Output: ((2, 3, 4, 7), (2, 3, 5, 7))
Too bad that the regex-engines work only with strings, not with general lists - would be really nice if you could find all matches for something like L.*?R with two arbitrary delimiters L and R. Since it doesn't work with regex, you have to build a little automaton yourself. Here is one way to do it:
#annotation.tailrec
def findDelimitedSlices[A](
xs: List[A],
l: A,
r: A,
revAcc: List[List[A]] = Nil
): List[List[A]] = {
xs match {
case h :: t => if (h == l) {
val idx = xs.indexOf(r)
if (idx >= 0) {
val (s, rest) = xs.splitAt(idx + 1)
findDelimitedSlices(rest, l, r, s :: revAcc)
} else {
revAcc.reverse
}
} else {
findDelimitedSlices(t, l, r, revAcc)
}
case Nil => revAcc.reverse
}
}
Input:
for (example <- List(
List(1, 2, 2, 2, 3, 4, 7, 8),
List(1, 2, 3, 4, 7, 7, 7, 8),
List(1, 2, 3, 4, 7, 1, 2, 3, 5, 7, 8)
)) {
println(findDelimitedSlices(example, 2, 7))
}
Output:
List(List(2, 2, 2, 3, 4, 7))
List(List(2, 3, 4, 7))
List(List(2, 3, 4, 7), List(2, 3, 5, 7))
You're looking for slice:
# l.slice(2, 7)
res1: List[Int] = List(2, 17, 35, 9, 12)
# l.slice(2, 8)
res2: List[Int] = List(2, 17, 35, 9, 12, 7)

Scala Split Seq or List by Delimiter

Let's say I have a sequence of ints like this:
val mySeq = Seq(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
I want to split this by let's say 0 as a delimiter to look like this:
val mySplitSeq = Seq(Seq(0, 1, 2, 1), Seq(0, -1), Seq(0, 1, 2, 3, 2))
What is the most elegant way to do this in Scala?
This works alright
mySeq.foldLeft(Vector.empty[Vector[Int]]) {
case (acc, i) if acc.isEmpty => Vector(Vector(i))
case (acc, 0) => acc :+ Vector(0)
case (acc, i) => acc.init :+ (acc.last :+ i)
}
where 0 (or whatever) is your delimiter.
Efficient O(n) solution
Tail-recursive solution that never appends anything to lists:
def splitBy[A](sep: A, seq: List[A]): List[List[A]] = {
#annotation.tailrec
def rec(xs: List[A], revAcc: List[List[A]]): List[List[A]] = xs match {
case Nil => revAcc.reverse
case h :: t =>
if (h == sep) {
val (pref, suff) = xs.tail.span(_ != sep)
rec(suff, (h :: pref) :: revAcc)
} else {
val (pref, suff) = xs.span(_ != sep)
rec(suff, pref :: revAcc)
}
}
rec(seq, Nil)
}
val mySeq = List(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
println(splitBy(0, mySeq))
produces:
List(List(0, 1, 2, 1), List(0, -1), List(0, 1, 2, 3, 2))
It also handles the case where the input does not start with the separator.
For fun: Another O(n) solution that works for small integers
This is more of warning rather than a solution. Trying to reuse String's split does not result in anything sane:
val mySeq = Seq(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
val z = mySeq.min
val res = (mySeq
.map(x => (x - z).toChar)
.mkString
.split((-z).toChar)
.map(s => 0 :: s.toList.map(_.toInt + z)
).toList.tail)
It will fail if the integers span a range larger than 65535, and it looks pretty insane. Nevertheless, I find it amusing that it works at all:
res: List[List[Int]] = List(List(0, 1, 2, 1), List(0, -1), List(0, 1, 2, 3, 2))
You can use foldLeft:
val delimiter = 0
val res = mySeq.foldLeft(Seq[Seq[Int]]()) {
case (acc, `delimiter`) => acc :+ Seq(delimiter)
case (acc, v) => acc.init :+ (acc.last :+ v)
}
NOTE: This assumes input necessarily starts with delimiter.
One more variant using indices and reverse slicing
scala> val s = Seq(0,1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).reverse.map( {var p=0; x=>{ val y=s.slice(x,s.size-p);p=s.size-x;y}}).reverse
res173: scala.collection.immutable.IndexedSeq[scala.collection.mutable.Seq[Int]] = Vector(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
if the starting doesn't have the delimiter, then also it works.. thanks to jrook
scala> val s = Seq(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).reverse.map( {var p=0; x=>{ val y=s.slice(x,s.size-p);p=s.size-x;y}}).reverse
res174: scala.collection.immutable.IndexedSeq[scala.collection.mutable.Seq[Int]] = Vector(ArrayBuffer(1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
UPDATE1:
More compact version by removing the "reverse" in above
scala> val s = Seq(0,1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).:+(s.size).sliding(2,1).map( x=>s.slice(x(0),x(1)) ).toList
res189: List[scala.collection.mutable.Seq[Int]] = List(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
scala> val s = Seq(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
s: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
scala> s.indices.filter( s(_)==0).+:(if(s(0)!=0) -1 else -2).filter(_>= -1 ).:+(s.size).sliding(2,1).map( x=>s.slice(x(0),x(1)) ).toList
res190: List[scala.collection.mutable.Seq[Int]] = List(ArrayBuffer(1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
scala>
Here is a solution I believe is both short and should run in O(n):
def seqSplitter[T](s: ArrayBuffer[T], delimiter : T) =
(0 +: s.indices.filter(s(_)==delimiter) :+ s.size) //find split locations
.sliding(2)
.map(idx => s.slice(idx.head, idx.last)) //extract the slice
.dropWhile(_.isEmpty) //take care of the first element
.toList
The idea is to take all the indices where the delimiter occurs, slide over them and slice the sequence at those locations. dropWhile takes care of the first element being a delimiter or not.
Here I am putting all the data in an ArrayBuffer to ensure slicing will take O(size_of_slice).
val mySeq = ArrayBuffer(0, 1, 2, 1, 0, -1, 0, 1, 2, 3, 2)
seqSplitter(mySeq, 0).toList
Gives:
List(ArrayBuffer(0, 1, 2, 1), ArrayBuffer(0, -1), ArrayBuffer(0, 1, 2, 3, 2))
A more detailed complexity analysis
The operations are:
Filter the delimiter indices (O(n))
loop over a list of indices obtained from previous step (O(num_of_delimeters)); for each pair of indices corresponding to a slice:
Copy the slice from the array and put it into the final collection (O(size_of_slice))
The last two steps sum up to O(n).

How to sum two neighbours in a list in scala

If you have one Integer list in Scala, and you want to iterate through it and sum every two neighbours with the same value and return this as a list, how would one do that ?
So for example:
List(4, 4, 2, 6) => List(8, 2, 6)
I'm completely new to Scala, but I can imagine that pattern match or map could be useful.
def sumSameNeighbours: List[Int] => List[Int] = {
ls match {
case l1::l2:ls => l1 == l2
}
}
This is what I can think of.
EDIT: How would I have to change the code in order to iterate from right to left instead from left to right?
So that f.e. it would be:
List(2, 2, 2, 6, 4) => List(2, 4, 6, 4)
instead of
List(2, 2, 2, 6, 4) => List(4, 2, 6, 4)
This is pretty close to your suggestion and seems basically to work:
import scala.annotation.tailrec
def sumSameNeighbors( ls : List[Int] ) : List[Int] = {
#tailrec
def walk( unsummed : List[Int], reverseAccum : List[Int] ) : List[Int] = {
unsummed match {
case a :: b :: rest if a == b => walk( rest, a + b :: reverseAccum )
case a :: rest => walk( rest, a :: reverseAccum )
case Nil => reverseAccum.reverse
}
}
walk( ls, Nil )
}
Note: Based on final OP's specifications clarification, this answer doesn't exactly fit the question requirements.
Here is a solution using List.grouped(2):
list.grouped(2).toList
.flatMap {
case List(a, b) if a == b => List(a + b)
case l => l
}
The idea is to group consecutive elements by pair. If the pair has the same elements, we return their sum to be flatMaped and otherwise both elements untouched.
List(4, 4, 2, 6) => List(8, 2, 6)
List(2, 4, 4, 2, 6) => List(2, 4, 4, 2, 6)
List(2) => List(2)
List(9, 4, 4, 4, 2, 6) => List(9, 4, 8, 2, 6)
Another way using foldRight, which I find a good default for this sort of traversing a collection while creating a new one:
list.foldRight(List.empty[Int]) {
case (x, y :: tail) if x == y => (x + y) :: tail
case (x, list) => x :: list
}
Output of List(2, 2, 2, 6, 4) is List(2, 4, 6, 4) as requested.
The main thing I wasn't clear on from your examples is what the output should be if summing creates new neighbours: should List(8, 4, 2, 2) turn into List(8, 4, 4) or List(16)? This produces the second.

Create sublists with elements 1 and 2 in alternate ways in Scala

Hi all I am new with Scala and I have a doubt:
Creation of sublists with elements 1 and 2 in alternate ways, never having two consecutive numbers repeated.
My function:
def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
//What should be the solution?
}
Tests:
test("AlternateElementsTests") {
assert(ca1.functionAlternateElements(List(1)) === Some(List(1)))
assert(ca1.functionAlternateElements(List(1,2)) === Some(List(2)))
assert(ca1.functionAlternateElements(List(1,2,3)) === Some(List(1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4)) === Some(List(1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5)) === Some(List(2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6)) === Some(List(1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7)) === Some(List(1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8)) === Some(List(2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9)) === Some(List(1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10)) === Some(List(1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11)) === Some(List(2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) === Some(List(2, 1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) === Some(List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1)))
assert(ca1.functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) === Some(List(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2)))
}
How can I do this?
If you know the code can you give an explanation so I can understand it please?
Given that the assertions seem to be more or less arbitrary, I don't know how to write a program that can produce these strange outputs.
However, I know how to write a program that can write a program that can produce these strange outputs. The idea is to generate code that satisfies the requirements. We will generate it by supplying an ansatz and then searching for a bunch of magic numbers by brute-force.
First, let's build some infrastructure. We need a tiny framework for solving arbitrary problems by brute force. Here is a trait that is useful for very small problems:
trait BruteForce[X] {
def engageBruteForceAttack(constraint: X => Boolean): Option[X]
def zip[Y](other: BruteForce[Y]): BruteForce[(X, Y)] =
new ProductBruteForce[X, Y](this, other)
}
We need to handle only the finite case and the case of cartesian product:
class FiniteBruteForce[X](possibilities: List[X])
extends BruteForce[X] {
def engageBruteForceAttack(constraint: X => Boolean) = possibilities.find(constraint)
}
object FiniteBruteForce {
def apply[X](xs: X*) = new FiniteBruteForce[X](xs.toList)
}
class ProductBruteForce[A, B](a: BruteForce[A], b: BruteForce[B])
extends BruteForce[(A, B)] {
def engageBruteForceAttack(constraint: ((A, B)) => Boolean) = {
var solution: Option[(A, B)] = None
a.engageBruteForceAttack { x =>
b.engageBruteForceAttack { y =>
if (constraint((x, y))) {
solution = Some((x, y))
true
} else {
false
}
}.map(_ => true).getOrElse(false)
}
solution
}
}
Now we can extract the inputs and outputs from your test cases:
val mysteriousTestCases = List(
(List(1), List(1)),
(List(1,2), List(2)),
(List(1,2,3), List(1, 2)),
(List(1,2,3,4), List(1, 2, 1)),
(List(1,2,3,4,5), List(2, 1, 2)),
(List(1,2,3,4,5,6), List(1, 2, 1, 2)),
(List(1,2,3,4,5,6,7), List(1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8), List(2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9), List(1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10), List(1, 2, 1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8,9,10,11), List(2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12), List(1, 2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13), List(1, 2, 1, 2, 1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14), List(2, 1, 2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15), List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16), List(1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1)),
(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17), List(2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2))
)
Now let's write a program that will write us the function that computes the strange 1,2,1,1,2,... sequence:
val (illuminatiPivot, (illuminatiOffset, illuminatiShift)) =
FiniteBruteForce(-1, -2, 0, 1, 2).zip(
FiniteBruteForce(-1, -2, 1, 2, 3).zip(
FiniteBruteForce(0, 1, 2)
)
).engageBruteForceAttack{ case (p, (o, s)) =>
mysteriousTestCases.forall { case (input, output) =>
val (start :: tail) = output
val n = input.size
val illuminatiNumber =
if (n < p) (n + o)
else List(1, 1, 2)((n + s) % 3)
start == illuminatiNumber
}
}.get
println(s"""|// The function that generates the start number
|// of the strange sequences
|def illuminatiNumber(n: Int): Int = {
| if (n < $illuminatiPivot) (n + $illuminatiOffset)
| else List(1, 1, 2)((n + $illuminatiShift) % 3)
|}
|""".stripMargin)
Now do the same for the lengths of the outputs. The ansatz is this time: it should be some affine-linear function that grows with factor 2/3 and is rounded in a weird way:
val (hl3ConfirmedConst, hl3ConfirmedOffset) =
FiniteBruteForce(-2, -1, 0, 1, 2).zip(
FiniteBruteForce(-2, -1, 0, 1, 2, 3)
).engageBruteForceAttack{ case (c, o) =>
mysteriousTestCases.forall { case (input, output) =>
val n = input.size
val halfLife3Confirmed = c + (n * 2 + o) / 3
output.size == halfLife3Confirmed
}
}.get
println(s"""|def halfLife3Confirmed(i: Int): Int = {
| $hl3ConfirmedConst + (i * 2 + $hl3ConfirmedOffset) / 3
|}
|""".stripMargin)
Finally, I didn't bother to think hard enough how to map 1 to sequence 1,2,1,2,... and 2 to 2,1,2,1,..., so I brute-forced this too:
val (tabulationOffset, tabulationShift) =
FiniteBruteForce(-1, 0, 1, 2).zip(FiniteBruteForce(0, 1)).engageBruteForceAttack{
case (x, y) =>
(0 to 2).map(i => x + (y + 1 + i) % 2).toList == List(1, 2, 1) &&
(0 to 2).map(i => x + (y + 2 + i) % 2).toList == List(2, 1, 2)
}.get
Now we can write out the initially seeked functionAlternateElements-method:
println(s"""|def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
| val n = list.size // throw away everything but the size
| val resultStart = illuminatiNumber(n)
| val resultSize = halfLife3Confirmed(n)
| Some(List.tabulate(resultSize){ i => $tabulationOffset + ($tabulationShift + resultStart + i) % 2 })
|}
|""".stripMargin)
Let's also write out the assertions again:
for ((i, o) <- mysteriousTestCases) {
val input = i.mkString("List(", ",", ")")
val output = o.mkString("List(", ",", ")")
println(s"""assert(functionAlternateElements($input) == Some($output))""")
}
And also let's append a line that tells us that everything went well in the end:
println("""println("All assertions are true")""")
When run, the above contraption produces the following code:
// The function that generates the start number
// of the strange sequences
def illuminatiNumber(n: Int): Int = {
if (n < -1) (n + -1)
else List(1, 1, 2)((n + 0) % 3)
}
def halfLife3Confirmed(i: Int): Int = {
0 + (i * 2 + 1) / 3
}
def functionAlternateElements(list : List[Int]): Option[List[Int]] = {
val n = list.size // throw away everything but the size
val resultStart = illuminatiNumber(n)
val resultSize = halfLife3Confirmed(n)
Some(List.tabulate(resultSize){ i => 1 + (1 + resultStart + i) % 2 })
}
assert(functionAlternateElements(List(1)) == Some(List(1)))
assert(functionAlternateElements(List(1,2)) == Some(List(2)))
assert(functionAlternateElements(List(1,2,3)) == Some(List(1,2)))
assert(functionAlternateElements(List(1,2,3,4)) == Some(List(1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5)) == Some(List(2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6)) == Some(List(1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7)) == Some(List(1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8)) == Some(List(2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9)) == Some(List(1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10)) == Some(List(1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11)) == Some(List(2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12)) == Some(List(1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13)) == Some(List(1,2,1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14)) == Some(List(2,1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)) == Some(List(1,2,1,2,1,2,1,2,1,2)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)) == Some(List(1,2,1,2,1,2,1,2,1,2,1)))
assert(functionAlternateElements(List(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17)) == Some(List(2,1,2,1,2,1,2,1,2,1,2)))
println("All assertions are true")
When we execute the generated code, we get only:
All assertions are true
and no AssertionErrors. Thus, we've managed to implement the strange function successfully.
Tip of the day: you know that your specification is bad when the only way to satisfy the tests is by brute-forcing a bunch of magic numbers.

How to compare a list element with the next element, to yield this element?

As I noted in the title, how to compare the element of index N with element of index N+1, if elements compared are exactly the same, yield element only once.
I know I can use toSet, to get a set of unique elements, but this does not help me because, my list can contain duplicated elements but duplicated element can't be the next element in my list.
val ll = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
// Desired output: List(1, 2, 3, 6, 3, 7, 5, 6, 3)
I got a "near working solution" using zipWithIndex.collect, but when I compare inside it, index runs OutOfBounds. I can make this to work if I can use two conditions inside, first check maximum index to be index = (list.size-1) then I can compare list(index) != list(index+1) then yield list(index)
What I have tried without success (because of OutOfBounds), is:
times.zipWithIndex.collect
{
case (element, index)
// index+1 will be incremented out of my list
if (times(index) != times(index+1)) => times(index)
}
This can work if I can use one more condition to limit index, but does not work with two conditions:
times.zipWithIndex.collect
{
case (element, index)
if (index < times.size)
if (times(index) != times(index+1)) => times(index)
}
I appreciate any kind of alternative.
how about
ll.foldLeft(List[Int]())((acc, x) => acc match {case Nil => List(x) case y => if (y.last == x) y else y :+ x})
Here's my alternative using the sliding function:
val ll = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
ll.sliding(2)
.filter( t => t.length > 1 && t(0) != t(1) )
.map( t => t(0) )
.toList :+ ll.last
You can use zip the list with itself, dropping the first element so that you compare elements at index N with N + 1. You only need to append the last element (you may want to use a ListBuffer as appending the last element requires to copy the list).
val r = times.zip(times.drop(1)).withFilter(t => t._1 != t._2).map(_._1) :+ times.last
scala> val times = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
times: List[Int] = List(1, 2, 3, 6, 3, 7, 5, 5, 6, 3)
scala> val r = times.zip(times.drop(1)).withFilter(t => t._1 != t._2).map(_._1) :+ times.last
r: List[Int] = List(1, 2, 3, 6, 3, 7, 5, 6, 3)