2010-05-20 2 views
6

Ví dụ, tôi có một danh sách (1 2 3 4 5 6 7 8 9 10 11) và muốn làm cho nó thành 3 phần tử (hoặc độ dài khác) để có được ((1 2 3) (4 5 6) (7 8 9) (10 11)). Tôi có thể sử dụng mã nào cho điều này? Cảm ơn.Làm thế nào roughen (như trái ngược với flatten) một danh sách trong một phong cách chức năng? Ví dụ:

+3

-1 cho phong cách. Khó để tìm ra câu hỏi thực tế – Dario

+2

"Roughen"? Cá nhân tôi gọi đó là "được nhóm", cũng như Scala. :-) –

Trả lời

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 Tuyệt vời! ...... – Dario

+0

Tốt! có bất kỳ mã clojure? – user342304

3

Trong Scala 2.8, Danh sách pha trộn trong IterableLike trong đó có phương pháp nhóm lại mà trả về một Iterator [Danh sách [T]], do đó có thể được chuyển đổi sang Liệt kê [Danh sách [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)) 

Nếu bạn muốn có một phương pháp làm cho nhám trên Danh sách bạn có thể sử dụng một chuyển đổi ngầm, một cái gì đó như:

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

Rất tiếc, không thấy câu trả lời của Thomas. –

+0

Mọi câu trả lời đều rất hay! nhưng tên nhóm là xấu, roughen là tổng quát hơn, như chống lại flatten: P, có thể roughen nhận được một chức năng mà roughen bởi nó, chiều dài, regex ..., sẽ tốt hơn – user342304

+0

Nhưng roughen sẽ ngụ ý (với tôi ít nhất) các danh sách không có cùng độ dài, giống như một mảng bị rách. Tôi nghĩ rằng phân vùng được sử dụng trong các ngôn ngữ/thư viện khác cho cùng một hoạt động. – pdbartlett

1

Đây là tốt nhất mà tôi có thể đưa ra:

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

Kể từ bạn cũng sử dụng thẻ Clojure ...

Có chức năng tích hợp để thực hiện điều đó trong Clojure 1.2, cũng có sẵn ở chế độ 1,1 trong 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)) 

cũng Xem partitionpartition-by. Cũng lưu ý rằng partitionpartition-all chấp nhận một số đối số tùy chọn nếu bạn cần một chút khác biệt, xem ví dụ: (doc partition) tại REPL.

+3

Tôi thường ngạc nhiên bởi bề rộng của chức năng trong thư viện của Clojure ... nhưng mong muốn có một cách thông minh để tìm ra những cái bạn muốn nhanh chóng! (Tất nhiên yêu cầu các siêu sao trên stackoverflow luôn là một tùy chọn :-)) – mikera

+3

Xem http://clojure.org/cheatsheet - phân vùng nằm ngay trong "seq lồng nhau". –

1

Dưới đây là một Clojure thực hiện 1.0 tương thích của làm cho nhám:

(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

Và phiên bản clojure khác, viết bằng clojure nhiều thành ngữ.

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

Lưu ý rằng split-at sẽ vượt qua chuỗi đầu vào hai lần. Vì vậy, bạn có thể thay thế phiên bản tiêu chuẩn như sau:

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

(. Tất nhiên người ta sẽ sử dụng partition và bạn bè như đã đề cập ở trên)