Как Scala может определить, все ли элементы массива имеют одинаковую длину? - PullRequest
11 голосов
/ 08 февраля 2010

Я новичок в Scala, но очень стар для Java и немного разбираюсь в работе с языками FP, такими как "Haskell".

Здесь мне интересно, как реализовать это с помощью 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 есть лучший способ сделать это ...

Ответы [ 7 ]

21 голосов
/ 08 февраля 2010
list.forall( str => str.size == list(0).size )

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

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) ))
7 голосов
/ 08 февраля 2010

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

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

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

3 голосов
/ 08 февраля 2010

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

2 голосов
/ 29 июля 2014
list.groupBy{_.length}.size == 1

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

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

2 голосов
/ 08 февраля 2010

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

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

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

1 голос
/ 08 февраля 2010

Вот еще один подход:

def check(list:List[String]) = list.foldLeft(true)(_ && list.head.length == _.length)
0 голосов
/ 18 апреля 2012

Просто мои € 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, оценивает минимальное возможное число раз, и, хотя блок не может быть каррирован, вывод типа может выводить тип параметра блока.

  "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 сопоставление с образцом так коварно не удается для Iterables.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...