2010-05-20 2 views
6

Zum Beispiel habe ich eine Liste (1 2 3 4 5 6 7 8 9 10 11), und will es um 3 Elemente (oder eine andere Länge) aufrauen, um ((1 2 3) (4 5 6) (7 8 9) (10 11)) zu bekommen. Welchen schönen Code könnte ich dafür verwenden? Vielen Dank.Wie wird eine Liste in einem funktionalen Stil aufgeraut (im Gegensatz zu flatten)?

+3

-1 für Stil. Schwierig, die eigentliche Frage herauszufinden – Dario

+2

"Roughen"? Ich würde das persönlich als "gruppiert" bezeichnen, wie auch Scala. :-) –

Antwort

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 Schön! ...... – Dario

+0

Gut! hast du einen clojure code? – user342304

3

In Scala 2.8 mischt Liste in IterableLike, die die gruppierten Methode hat, die einen Iterator [Liste [T]] gibt, die wiederum umgerechnet werden können zur Liste [Liste [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)) 

Wenn Sie eine aufrauen Methode auf Liste möchten, können Sie eine implizite Konvertierung verwenden, so etwas wie:

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

Hoppla, habe Thomas Antwort nicht gesehen. –

+0

Alle Antwort ist sehr nett! aber der gruppierte Name ist schlecht, der grobe ist allgemeiner, wie gegen flatten: P, vielleicht rauhen erhalten eine Funktion, die dadurch aufrauhen, solche Länge, Regex ..., wird besser – user342304

+0

Aber rauhen würde bedeuten (zu mir mindestens) dass die Listen nicht die gleiche Länge hatten wie ein unregelmäßiges Array. Ich denke, Partition wird in anderen Sprachen/Bibliotheken für die gleiche Operation verwendet. – pdbartlett

1

Dies ist die beste könnte ich kommen mit:

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

Seit Du verwendest auch das Clojure-Tag ...

Es gibt eine eingebaute Funktion, um das in Clojure 1.2 zu tun, das auch in 1.1 in cloj verfügbar ist 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)) 

Siehe auch partition und partition-by. Beachten Sie auch, dass partition und partition-all einige optionale Argumente akzeptieren, wenn Sie etwas anderes benötigen, siehe z. (doc partition) an der REPL.

+3

Ich bin oft erstaunt über die Funktionsvielfalt in den Clojure-Bibliotheken ... aber ich wünschte, es gäbe einen schlauen Weg, um die zu finden, die man schnell haben möchte! (natürlich fragen die Superstars auf Stackoverflow ist immer eine Option :-)) – mikera

+3

Siehe http://clojure.org/cheatsheet - Partition ist genau dort in "Nested Seqs". –

1

Hier ist eine Clojure 1.0-kompatible Implementierung von aufrauen:

(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

Und einer andere clojure Version, in mehr idiomatischen clojure geschrieben.

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

Hinweis, dass split-at durchläuft die Eingangssequenz zweimal. So können Sie die Standardversion mit folgenden ersetzen:

(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]))) 

(. Natürlich würde man verwenden partition und Freunde wie bereits oben erwähnt)

Verwandte Themen