2010-02-08 16 views
9

Soy nuevo en Scala pero soy muy viejo en Java y entendí que podía trabajar con lenguajes FP como "Haskell".¿Qué es Scala para encontrar si todos los elementos de una matriz tienen la misma longitud?

Aquí me pregunto cómo implementar esto usando Scala. Hay una lista de elementos en una matriz, todos son cadenas y solo quiero saber si hay una manera de hacerlo en Scala de una manera FP. Aquí está mi versión actual que funciona ...

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; 
} 

Y estoy bastante seguro de que hay una mejor manera de hacer esto en Scala/FP ...

+2

Es bastante atípico que sus 13 líneas de Java (es básicamente Java que ha escrito, en sintaxis Scala) pueden ser reducido a 1 línea de scala. ¡La 1 línea scala es infinitamente más legible, comprensible y por lo tanto más fácil de mantener! Digo ** atípico **, ¡normalmente solo podrías condensar 13 líneas de Java en 2 de scala! –

Respuesta

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

Editar: Aquí hay una definición que es tan general como possilbe y también permite comprobar si una propiedad distinta longitud es la misma para todos los elementos:

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 Sí. ¿No podría el término lattern simplemente ser 'list for all (_.size == list (0) .size) '? – Dario

+0

@Dario: Sí, podría. – sepp2k

+0

Excelente. Después de algunas pistas, terminé haciendo esto ... 'def checkLenght (vals: Array [String]): Boolean = vals.forall (_. Length == vals (0) .length)' –

3

Consejo: Utilice forall para determinar si todos los elementos en la colección satisfacen un determinado predicado (por ejemplo, igualdad de longitud).

2

Si usted sabe que sus listas son siempre no vacío, un forall recto funciona bien. Si no lo hace, es fácil añadir que, en:

list match { 
    case x :: rest => rest forall (_.size == x.size) 
    case _ => true 
} 

Ahora listas de retorno de longitud cero verdadera en vez de lanzar excepciones.

+0

¿Es posible la coincidencia de patrones en matrices? – Dario

+1

@Dario - sí, coinciden con las secuencias. Este comportamiento ha cambiado ligeramente en 2.8 pero aún se pueden usar en la coincidencia de patrones –

+0

@Dario - Sí. Si "list" es una matriz, use 'case Array (x, rest @ _ *) =>' en su lugar. Esto funciona tanto en 2.7 como en 2.8. –

1

Aquí hay otro enfoque:

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

el enfoque 'forall' es más eficiente. – F0RR

6

Como todo el mundo parece ser tan creativo, voy a ser creativa también. :-)

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

Eso sí, removeDuplicates probable que se nombró distinct sobre el Scala 2.8.

+1

¡listo! Pero hasta que se renombre, '(Set() ++ list.map (_. Length)). Size <= 1' es aún más corto. –

0

Sólo mi € 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 } 
    } 

Esto funciona con cualquier Iterable, evalúa f el número mínimo de veces posibles, y mientras que el bloque no puede ser al curry, el tipo inferencer puede inferir el tipo de parámetro de bloque.

"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 una pena que head :: tail coincidencia de patrones no tan insidiosamente para iterables.

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

Convierte la lista en un mapa de grupos de cadenas de igual longitud. Si todas las cadenas tienen la misma longitud, entonces el mapa contendrá solo uno de esos grupos.

Lo bueno de esta solución es que no necesita saber nada acerca de la longitud de las cadenas, y no necesita compararlas con, digamos, la primera cadena. Funciona bien en una cadena vacía, en cuyo caso devuelve falso (si eso es lo que quiere ...)

Cuestiones relacionadas