2012-06-21 41 views
5

Cho một List nhưChia một danh sách scala vào danh sách interleaving n

List(1, 2, 3, 4, 5, 6, 7) 

cách tốt nhất để chia nó thành n sub-danh sách, đặt mục vào mỗi danh sách theo kiểu round-robin là gì?

ví dụ: nếu n = 3, kết quả phải là

List(List(1, 4, 7), List(2, 5), List(3, 6)) 

Tôi nghĩ rằng sẽ có một phương pháp trong API bộ sưu tập để làm điều này, nhưng dường như tôi không thể tìm thấy nó.

điểm thưởng cho sang trọng một lớp lót;)

+0

Một câu hỏi tương tự, sử dụng Luồng: http: // stackoverflow .com/questions/17115345/split-a-stream-in-many – AmigoNico

Trả lời

10
scala> def round[T](l: List[T], n: Int) = (0 until n).map{ i => l.drop(i).sliding(1, n).flatten.toList }.toList 
round: [T](l: List[T], n: Int)List[List[T]] 

scala> round((1 to 7).toList, 3) 
res4: List[List[Int]] = List(List(1, 4, 7), List(2, 5), List(3, 6)) 
4

Đây là một đơn giản một-liner:

scala> List.range(1, 10) 
res11: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9) 

scala> res11.grouped(3).toList.transpose 
res12: List[List[Int]] = List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9)) 

Đáng tiếc là nó sẽ không hoạt động khi danh sách của bạn không phải là transposeable .

scala> List.range(1, 8).grouped(3).toList.transpose 
java.lang.IllegalArgumentException: transpose requires all collections have the 
same size 

Bạn có thể sử dụng các phương pháp sau đây để làm cho nó transposeable, và sau đó áp dụng các phương pháp trên.

scala> def extend[A](xs: List[A], c: Int): List[Option[A]] = { 
    | val n = Stream.iterate(c)(c +).find(_ >= xs.length).get 
    | xs.map(Some(_)).padTo(n, None) 
    | } 
extend: [A](xs: List[A], c: Int)List[Option[A]] 

scala> List.range(1, 8) 
res13: List[Int] = List(1, 2, 3, 4, 5, 6, 7) 

scala> extend(res13, 3).grouped(3).toList.transpose.map(_.flatten) 
res14: List[List[Int]] = List(List(1, 4, 7), List(2, 5), List(3, 6)) 

Đặt nhau:

scala> def round[A](xs: List[A], c: Int) = { 
    | val n = Stream.iterate(c)(c +).find(_ >= xs.length).get 
    | val ys = xs.map(Some(_)).padTo(n, None) 
    | ys.grouped(c).toList.transpose.map(_.flatten) 
    | } 
round: [A](xs: List[A], c: Int)List[List[A]] 

scala> round(List.range(1, 10), 3) 
res16: List[List[Int]] = List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9)) 

scala> round(List.range(1, 8), 3) 
res17: List[List[Int]] = List(List(1, 4, 7), List(2, 5), List(3, 6)) 
+0

'ys.grouped (3)' là một lỗi đánh máy? – senia

+0

@senia, tại sao đó lại là lỗi đánh máy? – missingfaktor

+0

nó phải là 'ys.grouped (c)' – senia

0

Nếu bạn không quan tâm về làm cho nó round robin bạn có thể làm:

val list = List(1, 2, 3, 4, 5, 6, 7) 
list.grouped(Math.ceil(list.size/3)) 
Các vấn đề liên quan