Как лучше всего перечислить список на естественном языке (Scala)? - PullRequest
5 голосов
/ 23 октября 2011

Объект List имеет метод mkString, который может преобразовывать в строку с разделителем.Однако в большинстве человеческих языков последний элемент отличается при перечислении списка.Например, A, B, C и D.

Что является лучшим с точки зрения размера кода и разумной эффективности для достижения этой цели?Если быть точным, я ищу функцию, которая удовлетворяет:

assertEquals("",foo(List()))
assertEquals("A",foo(List("A")))
assertEquals("A and B",foo("List("A","B")))
assertEquals("A, B and C", foo(List("A","B","C")))
assertEquals("A, B, C and D", foo(List("A","B","C","D")))

Ответы [ 3 ]

9 голосов
/ 23 октября 2011
def foo(xs: List[String]) = 
  (xs.dropRight(2) :\ xs.takeRight(2).mkString(" and "))(_+", "+_)

edit : Это может быть немного понятнее:

def foo(xs: List[String]) = 
  (xs.dropRight(2) :+ xs.takeRight(2).mkString(" and ")).mkString(", ")

@ axaluss Скорость зависит от длины списка.При средней длине списка более 4 элементов эта вторая версия быстрее, чем у Томаша.В противном случае, это немного медленнее.

8 голосов
/ 23 октября 2011

Мой дубль:

def foo[T](list: List[T]): String = list match {
    case Nil => ""
    case x :: Nil => x.toString
    case x :: y :: Nil => x + " and " + y
    case x :: rs => x + ", " + foo(rs)
}

Также для использования хвостовой рекурсии:

@tailrec def str[T](cur: String,  list: List[T]): String = list match {
    case Nil => cur
    case x :: Nil => cur + x
    case x :: y :: Nil => cur + x + " and " + y
    case x :: rs => str(cur + x + ", ", rs)
}

def foo[T](list: List[T]) = str("", list)
4 голосов
/ 23 октября 2011
def foo(list: List[String]) = list match{
  case Nil => ""
  case _ if list.length == 1 => list.first
  case _ => list.init.mkString(", ") + " and " + list.last
}
...