2011-10-23 15 views
5

L'oggetto List ha il metodo mkString che può essere convertito in una stringa con un separatore. Tuttavia la maggior parte dei linguaggi umani tratta l'ultimo elemento diverso quando si enumera una lista. Ad esempio A, B, C e D.Qual è il modo migliore per enumerare una lista in linguaggio naturale (Scala)?

Qual è il migliore in termini di dimensioni del codice e ragionevole efficienza per realizzare questo? Per essere precisi, che il mio per una funzione che soddisfa:

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

Ma per quanto riguarda l'Oxford Comma? http://en.wikipedia.org/wiki/Serial_comma –

risposta

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

modifica: questo mig essere un po 'più chiaro:

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

@axaluss La velocità dipende dalla lunghezza dell'elenco. Con una lunghezza media dell'elenco superiore a circa 4 elementi, questa seconda versione è più veloce di quella di Tomasz. Altrimenti, è leggermente più lento.

+0

la tua versione è la più veloce? almeno è il più breve;) – 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

Ecco la mia versione: 'def naturalMakeString (list: List [Any], sep1: String, sep2: String) = if (list.length <2) list. mkString else list.init.mkString (sep1) + sep2 + list.last' tuttavia sia il tuo che il mio non sono né brevi né efficienti (usi di init e last) – baldur

+2

Usando 'x :: Nil => x' come secondo caso, e 'case x => x.init ...' il terzo è un po 'più corto –

8

mio prendere:

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

anche di utilizzare la ricorsione in coda:

@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) 
Problemi correlati