0

Is there a more concise way of conditionally building up a list in Scala? Here's where I'm starting:

(j, k) match {
  case (0, 0) => List()
  case (j, 0) => List((c1, j))
  case (0, k) => List((c2, k))
  case (_, _) => List((c1, j), (c2, k))
}

In comparison, I could do this with a String:

"" + (if (j > 0) "j-part" else "") + (if (k > 0) "k-part" else "")

This works with the String + operator and with "". But can a similar thing be done with :: and lists?

Daniel Ashton
  • 1,388
  • 11
  • 23

4 Answers4

3

Here's one fairly satisfying solution:

List((c1, j), (c2, k)).filter(_._2 > 0)
Daniel Ashton
  • 1,388
  • 11
  • 23
1

This solution is efficient:

(if (j != 0) List((c1, j)) else List()) :::
(if (k != 0) List((c2, k)) else List())

And flexible, with independent conditions and the ability to add more than one element to the resulting list:

(if (j != 0) List((c1, j)) else List()) :::
(if (k % 2 != 0) List((c3, k + 1), (c2, k)) else List())

But this might be a place where imperative code is both more compact and performant:

var result = List[(Int, Int)]()
if (k != 0) result +:= (c2, k)
if (j != 0) result +:= (c1, j)
wingedsubmariner
  • 13,350
  • 1
  • 27
  • 52
1

Another alternative, works for more elements.

List(
  if (j != 0) List((c1, j)) else Nil,
  if (k != 0) List((c2, k)) else Nil
).flatten
The Archetypal Paul
  • 41,321
  • 20
  • 104
  • 134
1

Assume a collection of c's; for instance for n=5,

c = (1 to n).map { "c" + _ }
Vector(c1, c2, c3, c4, c5)

Then we can iterate over a given tuple of arity, for instance 5, like this,

(i,j,k,l,m).productIterator zip Iterator.from(1).map { _ match {
    case (0, idx) => List()
    case (x, idx: Int) => List((c(idx-1), x))
  }
}.toList

This approach is general enough to tackle any arity.

elm
  • 20,117
  • 14
  • 67
  • 113