2

I am trying to write idiomatic scala code to loop through two lists of lists, and to generate a new list containing only the differences of the two lists.

In procedural Scala I would do something like this:

val first: List[List[Int]]  = List(List(1,2,3,4,5),List(1,2,3,4,5),  List(1,2,3,4,5))
val second: List[List[Int]] = List(List(1,2,3,4,5),List(1,23,3,45,5),List(1,2,3,4,5))

var diff: List[String] = List[String]()
for (i <- List.range(0, first.size)){
  for (j <- List.range(0, first(0).size)){
    println(first(i)(j) + " " + second(i)(j))
    if (first(i)(j) != second(i)(j)) diff = diff ::: (s"${second(i)(j)}" :: Nil)
  }
}

Of course I do not like this, I have attempted to write a solution using for comprehension, but without success.

The closest thing I could get to was this:

for {(lf,ls) <- (first zip second) } yield if (lf == ls) lf else ls

but from that for comprehension I can not generate a list of String being of a different type from the input one.

Any suggestion?

alva
  • 72
  • 8
  • Are first and second supposed to be List(List(1,2,3,4,5),List(1,2,3,4,5), List(1,2,3,4,5))? – Henrik Kirk Dec 13 '16 at 12:58
  • probably duplicate http://stackoverflow.com/questions/3634897/nested-iteration-in-scala – Tyth Dec 13 '16 at 12:59
  • 1
    @alva Could you please make your code compile. The type is still wrong, first and second is not of type Int. Also in the example diff is a immutable list assigned to an val, so it is never updated. – Henrik Kirk Dec 13 '16 at 13:09
  • @Tyth, no I don't think is a duplicate. I do understand the difference between for and list comprehension. What I am asking here, is for any suggestion on how to write nested for loops in idiomatic scala, if there is an idiomatic approach. – alva Dec 13 '16 at 13:10
  • It would probably help if you provided sample inputs and outputs :) – Shastick Dec 13 '16 at 13:30
  • You could use multiple generators in same for comprehension: `for { i <- ...; j <- ...} yield ...` – insan-e Dec 13 '16 at 13:36

2 Answers2

3

The idiomatic Scala would be something like this:

(
  for {
    (row1, row2) <- (first, second).zipped   // go through rows with the same index
    (value1, value2) <- (row1, row2).zipped  // go through values with the same indexes
    if value1 != value2                      // leave only different values in the list
  } yield value2.toString
).toList

It's better to use zipped, than zip here, because zipped doesn't produce the whole zipped List in memory.

Also, you have to do toList in the end, due to a quirk in type inference.

Kolmar
  • 14,086
  • 1
  • 22
  • 25
0

Something like this produces the same results

val diff = for {
  firstInner <- first
  v1 <- firstInner
  secondInner <- second
  v2 <- secondInner
} yield if (v1 != v2) s"$v2}"

println(diff2 mkString ", ") // prints 23, 45

But this ofcourse fails with IndexOutOfBoundsException if the array sizes isn't of the same size.

Henrik Kirk
  • 604
  • 1
  • 6
  • 18