Use the same variable several times within the same template

I would like to be able to use one variable several times within the same template, so that it will only correspond to the fact that the same value is present in all places, for example

list match { case x :: x :: xs => // recurse } 

which will match List(1,1,2) but not List(1,2,1) . But this is not compiled with error: x is already defined as value x .

Studying this question, I found that I can also include case in the sentence, so I can do

 list match { case x1 :: x2 :: xs if x1==x2 => // recurse } 

which seems to work the same way (right, right?). This is good, but it would not look as clean if I wanted to have the same meaning in many places, for example

 list match { case x1::x2::x3::x4::xs if x1==x2 && x2==x3 && x3==x4 => // recurse } 

Is there a more elegant way I can do this?


A few notes: Yes, I just study scala if that was not clear, so I'm not sure if this is what I really would like to do, but I'm just interested in what is possible. In this regard, I am not looking for a completely different solution, for example, takeWhile or filter or something else, but all the more you are interested in matching templates.

+6
source share
3 answers

Scala does not provide such flexibility in its matches (which may be good, because you need to know about errors that result from unintentional reuse of variables).

If you have a large number of identical elements, you can consider a nested match (but note that you will not exit the internal match, which will be completed later by the external match, so you will have to process everything locally):

 list match { case x :: rest => rest match { case `x` :: `x` :: `x` :: xs => println("Four of the same") case _ => println("Well, nonempty at least") } case _ => println("Boring, there nothing here!") } 

Pay attention to the return outputs, which mean "we already have this variable, check it, do not set it!".

Alternatively, if you have specialized functions that you reuse, you can create a custom connector:

 object FourOf { def unapplySeq(xs: List[Int]): Option[(Int, List[Int])] = xs match { case x :: y :: z :: a :: rest if x==y && y==z && z==a => Some((x,rest)) case _ => None } } 

and then use it whenever you need this complex template:

 list match { case FourOf(x,rest) => println("four of the same") case x :: more => println("Nonempty") case _ => println("Yawn") } 

None of them are as neat and flexible as you probably hoped, but again, I'm not sure that switching between assigning and testing the same variable in a matching statement is a good way to write clear code anyway.

+8
source

For many repetitions, you can use stable identifiers for comparison (instead of catching a value):

 val x = list.head list match { case `x`::`x`::`x`::`x`::xs => .... } 

But note that this will not work on an empty list (you just cannot get it).

+5
source

I think Rex answers with stones. I am a fan of unapplySeq . But here there is a not very smart and maybe wasteful alternative, if your main concern is reduced only to the sequence == in each guard. So, in TMTOWTDI :

 def same[A](xs: A*) = xs forall (xs.head==) // Then in your pattern match, list match { // case x1::x2::x3::x4::xs if x1==x2 && x2==x3 && x3==x4 => // recurse case x1::x2::x3::x4::xs if same(x1,x2,x3,x4) => // recurse } 

I also like Ohm's answer, so here's the adaptation:

  list.headOption map (x => list match { case `x`::`x`::`x`::`x`::xs => //...; case _ => // ... }) getOrElse { // do what you'd have done for an empty list... } 
+3
source

All Articles