Multiple assignment of non-tuples in scala

10,371

Solution 1

All you need to do is make your val side (left of the =) compatible with your initializer (right of the =):

scala> val Array(x, y, z) = "XXX,YYY,ZZZ".split(",")
x: java.lang.String = XXX
y: java.lang.String = YYY
z: java.lang.String = ZZZ

As you expected, a scala.MatchError will be thrown at runtime if the array size don't match (isn't 3, in the above example).

Solution 2

Since your string can have arbitrary contents, the result cannot be guaranteed to have a 2-tuple-form by the type-system (and no conversion would make sense at all). Therefore you'll have to deal with sequences (like arrays) anyway.

Thankfully there are right-ignoring sequence patterns which allow you to match the result values conveniently nevertheless.

val Seq(x, y, _ @ _*) = "a b".split(" ")

Solution 3

scala> val Array(x, y, _*) = "a b" split " "
x: java.lang.String = a
y: java.lang.String = b
Share:
10,371
Elazar Leibovich
Author by

Elazar Leibovich

Updated on June 06, 2022

Comments

  • Elazar Leibovich
    Elazar Leibovich almost 2 years

    Just to clarify, when I say multiple assigment, parallel assignment, destructuring bind I mean the following pattern matching gem

    scala> val (x,y) = Tuple2("one",1)
    x: java.lang.String = one
    y: Int = 1
    

    which assigns "one" to x and 1 to y.

    I was trying to do

    val (x,y) = "a b".split()
    

    I was expecting that scala would attempt to pattern match the array with the pattern, and would throw a runtime exception if the length of the array wouldn't match the length of the pattern.

    All my attempts to easily convert an Array to a Tuple2 were futile.

    scala> Tuple2(Array(1,2):_*)
    <console>:7: error: wrong number of arguments for method apply: (T1,T2)(T1, T2)
    in object Tuple2
           Tuple2(Array(1,2):_*)
           ^
    
    scala> Tuple2(Array(1,2).toList:_*)
    <console>:7: error: wrong number of arguments for method apply: (T1,T2)(T1, T2)
    in object Tuple2
           Tuple2(Array(1,2).toList:_*)
    

    Is there any neat way to use multiple assignment with arrays or lists?

  • Elazar Leibovich
    Elazar Leibovich about 14 years
    Quoting myself: "I was expecting that scala would attempt to pattern match the array with the pattern, and would throw a runtime exception if the length of the array wouldn't match the length of the pattern", also see Randall's solution. Anyway this is a nice one as well. So simple I wish I thought about it myself. +1.
  • Randall Schulz
    Randall Schulz about 14 years
    In Scala 2.8, Array is no longer Seq, so this technique doesn't work there.
  • retronym
    retronym about 14 years
    This works because the object Array includes the unapplySeq method, making it usable as an Exractor Pattern. Array.unapplySeq("XXX,YYY,ZZZ".split(",") is called, returning Some(ArrayBuffer(XXX, YYY, ZZZ)), which is a Some, and contains three elements to bind to x, y, and z.
  • psp
    psp about 14 years
    The technique certainly works, you just write "Array" instead of "Seq". Or if you can be chill about the end of the String, val Array(x, y) = "a b" split " " take 2
  • Blaisorblade
    Blaisorblade about 12 years
    val Array(x, y, _*) = "a b".split(" ") also works with less syntactic clutter. I don't think that _ @ is ever useful.
  • Batato
    Batato almost 6 years
    why val Array(X, Y, Z) = "XXX,YYY,ZZZ".split(",") doesn't work? I get <console>:14: error: not found: value X...
  • Jim Balter
    Jim Balter almost 5 years
    @Batato match variables must be lowercase