2010-05-20 4 views
6

Por ejemplo, tengo una lista (1 2 3 4 5 6 7 8 9 10 11), y quiero endurecerla por 3 elementos (u otra longitud) para obtener ((1 2 3) (4 5 6) (7 8 9) (10 11)). ¿Qué bonito código podría usar para esto? Gracias.¿Cómo áspera (en lugar de aplanar) una lista en un estilo funcional?

+3

-1 para el estilo. Difícil de averiguar la pregunta real – Dario

+2

"Roughen"? Personalmente me referiría a eso como "agrupado", como también lo hace Scala. :-) –

Respuesta

2
def split[A](list : List[A], n : Int) : List[List[A]] = list match { 
    case List() => List() 
    case  _ => (list take n) :: split(list drop n, n) 
} 
15
List(1,2,3,4,5,6,7,8,9,10,11) grouped 3 toList 

res0: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), 
List(7, 8, 9), List(10, 11)) 
+0

+1 ¡Agradable! ...... – Dario

+0

¡Bien! ¿Tienes algún código de Clojure? – user342304

3

En Scala 2.8, Lista de Mezclas en IterableLike que tiene el método agrupados que devuelve un iterador [Lista [T]], que a su vez se puede convertir a la lista [Lista [T]].

List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11).grouped(3).toList 

res3: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9), List(10, 11)) 

Si desea un método roughen en la Lista puede utilizar una conversión implícita, algo así como:

scala> class RList[T](val l: List[T]) {def roughen(n: Int) = l.grouped(n).toList} 
defined class RList 

scala> implicit def list2rlist[T](l: List[T]) = new RList(l) 
list2rlist: [T](l: List[T])RList[T]  

scala> List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) roughen 3 
res5: List[List[Int]] = List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9), List(10, 11)) 
+0

Vaya, no vi la respuesta de Thomas. –

+0

¡Todas las respuestas son muy buenas! pero el nombre agrupado es malo, el rough es más general, como contra flatten: P, tal vez áspero recibir una función que aspereza por él, tal longitud, regex ..., será mejor – user342304

+0

Pero rough implicaría (para mí al menos) que las listas no tenían la misma longitud, como una matriz irregular. Creo que la partición se usa en otros idiomas/bibliotecas para la misma operación. – pdbartlett

1

Esto es lo mejor que se le ocurrió:

def roughen(l:List[_],s:Int):List[_] ={ 

    if (l.isEmpty) return Nil 
    val l2 = l.splitAt(s) 
    l2._1 :: roughen(l2._2,s) 

} 

val l = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 
roughen(l,3) 
//returns: List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9), List(10)) 
15

Desde usted usa la etiqueta Clojure también ...

Hay una función incorporada para hacer eso en Clojure 1.2, también disponible en 1.1 en cloj ure.contrib.seq-utils.

(partition-all 3 [1 2 3 4 5 6 7 8 9 10 11]) 
; => ((1 2 3) (4 5 6) (7 8 9) (10 11)) 

Ver también partition y partition-by. También tenga en cuenta que partition y partition-all aceptan algunos argumentos opcionales si necesita algo ligeramente diferente, consulte p. Ej. (doc partition) en REPL.

+3

Con frecuencia me sorprende la amplitud de la funcionalidad de las bibliotecas de Clojure ... ¡pero desearía que hubiera una manera inteligente de encontrar las que desea rápidamente! (por supuesto, pedirle a las superestrellas sobre stackoverflow siempre es una opción :-)) – mikera

+3

Ver http://clojure.org/cheatsheet - la partición está ahí en "Sects anidados". –

1

Aquí hay una aplicación compatible con Clojure 1.0 de roughen:

(defn roughen 
    "Roughen sequence s by sub-grouping every n elements. 
    e.gn (roughen '(a b c d) 2) -> ((a b) (c d))" 
    [s n] 
    (loop [result() s s] 
    (cond (empty? s) 
     result 
     (< (count s) n) 
     (concat result (list s)) 
     :default 
     (recur (concat result (list (take n s))) (drop n s))))) 

user=> (roughen '(a b c d e f g) 2) 
((a b) (c d) (e f) (g)) 
user=> (roughen '(a b c d e f) 2) 
((a b) (c d) (e f)) 
user=> (roughen '(a b c d e f) 4) 
((a b c d) (e f)) 
user=> 
2

Y otra versión clojure, escrito en clojure más idiomática.

(defn roughen 
    [n coll] 
    (lazy-seq 
    (when-let [s (seq coll)] 
     (let [[l r] (split-at n s)] 
     (cons l (roughen n r)))))) 

Nota, que split-at atraviesa la secuencia de entrada dos veces. Para que pueda reemplazar la versión estándar con lo siguiente:

(defn split-at 
    [n coll] 
    (loop [n n, s coll, l []] 
    (if-not (zero? n) 
     (if-let [s (seq s)] 
     (recur (dec n) (rest s) (conj l (first s))) 
     [l nil]) 
     [l s]))) 

(. Por supuesto, se podría usar partition y amigos como ya se mencionó anteriormente)

Cuestiones relacionadas