2010-02-08 3 views
9

Я новичок в Scala, но очень старый для Java и имел некоторое понимание работы с языками FP, такими как «Haskell».Что такое способ Scala для определения того, имеют ли все элементы массива одинаковые длины?

Здесь мне интересно, как реализовать это, используя Scala. Есть список элементов в массиве, все из них являются строками, и я просто хочу знать, есть ли способ, которым я могу это сделать в Scala в FP-способе. Вот моя текущая версия, которая работает ...

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

И я уверен, что есть лучший способ сделать это в Scala/FP ...

+2

Довольно атипично, что ваши 13 строк Java (это в основном Java, которую вы написали, в синтаксисе Scala) могут быть сокращен до 1 строки scala. 1 линия scala бесконечно читаема, понятна и, следовательно, поддерживается! Я говорю ** нетипичный **, обычно вы можете конденсировать только 13 строк Java на 2 scala! –

ответ

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

Edit: Вот определение, которое столь же вообще как possilbe, а также позволяет проверить свойство, кроме длины, является ли то же самое для всех элементов:

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 Да. Не мог ли термин lattern даже быть «list forall» (_.size == list (0) .size) '? – Dario

+0

@ Dario: Да, это возможно. – sepp2k

+0

Отлично. После некоторых трасс я закончил это делать ... 'def checkLenght (vals: Array [String]): Boolean = vals.forall (_. Length == vals (0) .length)' –

3

Совет: Используйте forall, чтобы определить, все ли элементы в наборе удовлетворяют определенному предикату (например, равенство длины).

2

Если вы знаете, что ваши списки всегда Непустой, прямой forall работает хорошо. Если вы этого не сделаете, это легко добавить, что в:

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

Теперь списки нулевой длины возвращает истину, а не бросать исключения.

+0

Возможно ли сопоставление шаблонов на массивах? – Dario

+1

@ Dario - да, они соответствуют последовательностям. Это немного изменилось в 2.8, но они все еще могут использоваться при сопоставлении шаблонов –

+0

@Dario - Да. Если «list» - это массив, вместо этого используйте 'case Array (x, rest @ _ *) =>'. Это работает как в 2.7, так и 2.8. –

1

Вот другой подход:

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

Подход 'forall' более эффективен. – F0RR

6

Поскольку все кажется таким творческим, я буду творческий тоже. :-)

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

Имейте в виду, removeDuplicates, скорее всего, будет называться distinct на Scala 2.8.

+1

Умный! Но пока он не переименован, '(Set() ++ list.map (_. Length)). Size <= 1' еще короче. –

0

Просто мой € 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 } 
    } 

Это работает с любым Iterable, оценивает е минимальное количество раз, возможно, и в то время как блок не может быть кэрри, тип inferencer может определить тип параметра блока.

"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) 
    } 

Это просто позор, что head :: tail сопоставления с образцом терпит неудачу так коварно для итерируемого.

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

Вы преобразовываете список в карту групп строк равной длины. Если все строки имеют одинаковую длину, тогда карта будет содержать только одну такую ​​группу.

Хорошая вещь с этим решением заключается в том, что вам не нужно ничего знать о длине строк и не нужно компарировать их, скажем, в первую строку. Он хорошо работает на пустой строке, и в этом случае он возвращает false (если это то, что вы хотите ..)

Смежные вопросы