2010-02-08 4 views
9

Ich bin neu in Scala und sehr alt zu Java und hatte etwas Verständnis mit FP-Sprachen wie "Haskell" zu arbeiten.Was ist Scala, um herauszufinden, ob alle Elemente eines Arrays die gleiche Länge haben?

Hier frage ich mich, wie dies mit Scala zu implementieren. Es gibt eine Liste von Elementen in einem Array, alle sind Strings und ich möchte nur wissen, ob es einen Weg gibt, wie ich das in Scala auf eine FP-Weise machen kann. Hier ist meine aktuelle Version, die funktioniert ...

def checkLength(vals: Array[String]): Boolean = { 
    var len = -1 
    for(x <- conts){ 
    if(len < 0) 
     len = x.length() 
    else{ 
     if (x.length() != len) 
     return false 
     else 
     len = x.length() 
    } 
    } 
    return true; 
} 

Und ich bin mir ziemlich sicher, dass es ein besserer Weg, dies zu tun in Scala/FP ...

+2

Es ist einigermaßen untypisch, dass Ihre 13 Zeilen Java (es ist im Grunde Java, die Sie geschrieben haben, in Scala-Syntax) sein kann reduziert auf 1 Zeile scala. Die 1 Scalalinie ist unendlich lesbarer, verständlicher und damit wartbar! Ich sage ** atypisch **, normalerweise könnte man nur 13 Zeilen Java in 2 von scala zusammenfassen! –

Antwort

19
list.forall(str => str.size == list(0).size) 

Edit: Hier ist eine Definition, die als possilbe als General ist und erlaubt auch zu prüfen, ob eine andere Eigenschaft als die Länge ist das gleiche für alle Elemente:

def allElementsTheSame[T,U](f: T => U)(list: Seq[T]) = { 
    val first: Option[U] = list.headOption.map(f(_)) 
    list.forall(f(_) == first.get) //safe to use get here! 
} 

type HasSize = { val size: Int } 
val checkLength = allElementsTheSame((x: HasSize) => x.size)_ 

checkLength(Array("123", "456")) 

checkLength(List(List(1,2), List(3,4))) 
+2

+1 Ja. Könnte der letztere Ausdruck auch nicht einfach "Liste für alle" sein?size == list (0) .size) '? – Dario

+0

@Dario: Ja, könnte es. – sepp2k

+0

Ausgezeichnet. Nach einigen Trails endete ich damit ... 'def checkLenght (vals: Array [Zeichenfolge]): Boolean = vals.forall (_. Length == vals (0). Length)' –

3

Tipp: Verwenden Sie forall, ob alle Elemente zu bestimmen, in der Sammlung ein bestimmtes Prädikat erfüllen (zB Längengleichheit).

2

Wenn Sie wissen, dass Ihre Listen sind immer nicht leer, ein gerades forall funktioniert gut. Wenn Sie dies nicht tun, fügen Sie einfach Folgendes hinzu:

Jetzt werden Listen mit der Länge Null als wahr zurückgegeben, anstatt Ausnahmen auszugeben.

+0

Ist ein Mustervergleich auf Arrays möglich? – Dario

+1

@Dario - ja, sie passen gegen Sequenzen. Dieses Verhalten hat sich in 2.8 leicht geändert, aber sie können weiterhin in der Mustererkennung verwendet werden. –

+0

@Dario - Ja. Wenn "list" ein Array ist, verwenden Sie stattdessen "case Array (x, rest @ _ *) =>". Dies funktioniert sowohl in 2.7 als auch in 2.8. –

1

Hier ist ein weiterer Ansatz:

def check(list:List[String]) = list.foldLeft(true)(_ && list.head.length == _.length) 
+0

Forall-Ansatz ist effizienter. – F0RR

6

Da jeder so kreativ zu sein scheint, ich werde auch kreativ zu sein. :-)

def checkLength(vals: Array[String]): Boolean = vals.map(_.length).removeDuplicates.size <= 1 

Wohlgemerkt, removeDuplicates wird wahrscheinlich distinct auf Scala 2.8 genannt werden.

+1

Clever! Aber bis zum Umbenennen ist '(Set() ++ list.map (_. Length)) .size <= 1' noch kürzer. –

0

Just my € 0,02

def allElementsEval[T, U](f: T => U)(xs: Iterable[T]) = 
    if (xs.isEmpty) true 
    else { 
    val first = f(xs.head) 
    xs forall { f(_) == first } 
    } 

Dies funktioniert mit jedem Iterable wertet f die minimale Anzahl von Zeiten möglich ist, und während der Block nicht curried werden kann, kann der Typ Rückschließer den Block Parametertyp schließen.

"allElementsEval" should "return true for an empty Iterable" in { 
    allElementsEval(List[String]()){ x => x.size } should be (true) 
    } 
    it should "eval the function at each item" in { 
    allElementsEval(List("aa", "bb", "cc")) { x => x.size } should be (true) 
    allElementsEval(List("aa", "bb", "ccc")) { x => x.size } should be (false) 
    } 
    it should "work on Vector and Array as well" in { 
    allElementsEval(Vector("aa", "bb", "cc")) { x => x.size } should be (true) 
    allElementsEval(Vector("aa", "bb", "ccc")) { x => x.size } should be (false) 
    allElementsEval(Array("aa", "bb", "cc")) { x => x.size } should be (true) 
    allElementsEval(Array("aa", "bb", "ccc")) { x => x.size } should be (false) 
    } 

Es ist nur schade, dass head :: tail Mustervergleich für Iterables so schleichend ausfällt.

2
list.groupBy{_.length}.size == 1 

Sie konvertieren die Liste in eine Zuordnung von Gruppen von Strings gleicher Länge. Wenn alle Strings dieselbe Länge haben, wird die Karte nur eine solche Gruppe enthalten.

Das nette Ding mit dieser Lösung ist, dass Sie nichts über die Länge der Zeichenfolgen wissen müssen, und sie nicht zu, sagen wir, der ersten Zeichenfolge compapre. Es funktioniert gut auf einer leeren Zeichenfolge, in diesem Fall gibt es false zurück (wenn das ist, was Sie wollen ..)

Verwandte Themen