Wie mustere ich Match-Arrays in Scala?

68

Meine Methodendefinition sieht wie folgt aus

def processLine(tokens: Array[String]) = tokens match { // ...

Angenommen, ich möchte wissen, ob die zweite Zeichenfolge leer ist

case "" == tokens(1) => println("empty")

Kompiliert nicht. Wie mache ich das?

deltanovember
quelle
Ich verstehe nicht wirklich, was Sie erreichen wollen. Testen Sie, ob der zweite Eintrag des Arrays der leere String ist, und geben Sie in diesem Fall "leer" aus. Zweitens fehlt Ihrer "Methodensignatur" die Zuweisung des Rückgabetyps und sie enthält einen Code (nämlich tokens match {}).
Ziggystar

Antworten:

110

Wenn Sie eine Musterübereinstimmung für das Array durchführen möchten, um festzustellen, ob das zweite Element die leere Zeichenfolge ist, können Sie Folgendes tun:

def processLine(tokens: Array[String]) = tokens match {
  case Array(_, "", _*) => "second is empty"
  case _ => "default"
}

Das _*bindet an eine beliebige Anzahl von Elementen, einschließlich keiner. Dies ähnelt der folgenden Übereinstimmung in Listen, die wahrscheinlich besser bekannt ist:

def processLine(tokens: List[String]) = tokens match {
  case _ :: "" :: _ => "second is empty"
  case _ => "default"
}
Rüdiger Keller
quelle
2
Wie passt das Muster zum Schwanz? es wird als _ *
devssh
2
@devsshtail @ _*
Abhijit Sarkar
Ist _*also eine anonyme Variable? Was würde ich tun, wenn ich den Wert dieses Schwanzes innerhalb des Fallblocks drucken möchte? Wenn ich das tue, case akann ich es ainnerhalb des Fallblocks verwenden, aber wenn ich es tue case _, wird diese Variable innerhalb des Fallblocks unbrauchbar. Kannst du mehr erklären? Ich habe versucht, Array (a, b, c) zu verwenden, aber das passt für Array der Größe 3, nicht für Größe n.
Devssh
7

Was besonders cool ist, ist, dass Sie einen Alias ​​für die _*Dinge verwenden können, die mit so etwas übereinstimmen

val lines: List[String] = List("Alice Bob Carol", "Bob Carol", "Carol Diane Alice")

lines foreach { line =>
  line split "\\s+" match {
    case Array(userName, friends@_*) => { /* Process user and his friends */ }
  }
}
Synapse
quelle
6

Der Mustervergleich ist möglicherweise nicht die richtige Wahl für Ihr Beispiel. Sie können einfach tun:

if( tokens(1) == "" ) {
  println("empty")
}

Der Mustervergleich eignet sich besser für Fälle wie:

for( t <- tokens ) t match {
   case "" => println( "Empty" )
   case s => println( "Value: " + s )
}

die für jeden Token etwas drucken.

Bearbeiten: Wenn Sie überprüfen möchten, ob ein Token vorhanden ist, bei dem es sich um eine leere Zeichenfolge handelt, können Sie auch Folgendes versuchen:

if( tokens.exists( _ == "" ) ) {
  println("Found empty token")
}
paradigmatisch
quelle
2
Das funktioniert definitiv, scheint aber die prozedurale Art zu sein, Dinge zu tun. Ich habe versucht, in funktionalen Begriffen zu denken
11.
Ja, weil Ihre Frage prozessuale Antworten erfordert. Für einen funktionaleren Ansatz können Sie jedes Element einer Zeichenfolgenoption zuordnen, die None ist, wenn die Zeichenfolge leer ist. Sie können die Linie auch in eine Karte (oder Fallklasse) einschließen, um die explizite Arbeit mit Indizes zu beenden.
Paradigmatisch
6
@deltanovember Das printlnmacht Ihren Code prozedural. Ihre offensichtliche Verwirrung ergibt sich aus der Tatsache, dass ifBlöcke in Scala Ausdrücke und keine Aussagen sind (dh sie geben einen Wert zurück und sind daher perfekt funktionsfähig). Die Verwendung eines ifAusdrucks ist nicht von Natur aus prozedural, sondern ein Mustervergleich.
Aaron Novstrup
3

caseAussage funktioniert so nicht. Das sollte sein:

case _ if "" == tokens(1) => println("empty")
fehlender Faktor
quelle
Was passiert, wenn ich separate Prüfungen für Token (1), Token (2), ... möchte?
Deltanovember
+1 für eine funktionierende Lösung, aber ich frage mich, ob das OP nicht auf einen komplexen Array-ähnlichen Ausdruck nach dem caseSchlüsselwort (_, "", _). Saying gehofft hat. So etwas wie case _` ist ziemlich langweilig, aber ich denke, es ist alles, was Sie hier tun können. Könnte auch einfach das Match return tokens(1) == ""abschaffen und sagen :-).
Ray Toal
1
@ Ray Toal: siehe Rüdiger Kellers Antwort.
Alexey Romanov
2
Beeindruckend. Scala beeindruckt immer wieder. Bei dieser Geschwindigkeit werde ich mich komplett von ML entfernen.
Ray Toal