2011-10-23 8 views
5

El objeto List tiene el método mkString que se puede convertir en una cadena con un separador. Sin embargo, la mayoría de los lenguajes humanos tratan el último elemento diferente al enumerar una lista. Por ejemplo A, B, C y D.¿Cuál es la mejor manera de enumerar una lista en lenguaje natural (Scala)?

¿Cuál es el mejor en términos de tamaño de código y eficiencia razonable para lograr esto? Para ser precisos, Estoy buscando una función que satisface:

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"))) 
+2

¿Pero qué pasa con la coma de Oxford? http://en.wikipedia.org/wiki/Serial_comma –

Respuesta

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

editar: este mig ht ser un poco más claro:

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

@axaluss La velocidad depende de la longitud de la lista. Con una longitud promedio de la lista de más de 4 elementos, esta segunda versión es más rápida que la de Tomasz. De lo contrario, es un poco más lento.

+0

¿Es su versión la más rápida? al menos es el más corto;) – axaluss

4
def foo(list: List[String]) = list match{ 
    case Nil => "" 
    case _ if list.length == 1 => list.first 
    case _ => list.init.mkString(", ") + " and " + list.last 
} 
+0

Aquí está mi propia versión: 'def naturalMakeString (list: List [Any], sep1: String, sep2: String) = if (list.length <2) list. mkString else list.init.mkString (sep1) + sep2 + list.last' sin embargo, tanto el suyo como el mío no son cortos ni eficientes (usos de init y último) – baldur

+2

Usando 'x :: Nil => x' como el segundo caso, y 'case x => x.init ...' como el tercero es un poco más corto –

8

Mi opinión:

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

Además de utilizar la cola de recursión:

@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) 
Cuestiones relacionadas