2016-12-04 7 views

答えて

3

それがこれを行うための最も簡単な方法だ場合、私は知らないが、私はそのようなことは、かなり良いディストリビューションで動作するはずだと思う:

import scala.util.Random 

def split[T](list: List[T], chunks: Int): List[List[T]] = 
    if (chunks == 0) Nil 
    else if (chunks == 1) List(list) 
    else { 
    val avg = list.size/chunks 
    val rand = (1.0 + Random.nextGaussian/3) * avg 
    val index = (rand.toInt max 1) min (list.size - chunks) 
    val (h, t) = list splitAt index 
    h +: split(t, chunks - 1) 
    } 

結果:

split(1 to 100 toList, 10) 
List[List[Int]] = List(
    List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), 
    List(15, 16, 17, 18, 19, 20, 21), 
    List(22, 23, 24, 25, 26, 27, 28), 
    List(29, 30, 31, 32, 33, 34, 35, 36, 37, 38), 
    List(39, 40, 41, 42, 43), 
    List(44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54), 
    List(55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70), 
    List(71, 72, 73, 74, 75), 
    List(76, 77, 78, 79, 80, 81, 82, 83, 84), 
    List(85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100) 
) 

編集:ここにより効率的ですが、エレガントなテール再帰バージョンです。リストの終わり近くのindexを持つsplitAtを呼び出すと、O(n * n)の複雑さで終わるので、結果のリストは逆になります。

def split[T](list: List[T], chunks: Int): List[List[T]] = { 
    @tailrec 
    def split[T](list: List[T], chunks: Int, size: Int, result: List[List[T]]): List[List[T]] = 
    if (chunks == 0) result 
    else if (chunks == 1) list +: result 
    else { 
     val avg = size/chunks 
     val rand = (1.0 + Random.nextGaussian/3) * avg 
     val index = (rand.toInt max 1) min (size - chunks) 
     val (h, t) = list splitAt index 
     split(t, chunks - 1, size - index, h +: result) 
    } 
    split(list, chunks, list.size, Nil).reverse 
} 
+0

adamwy大きな入力に起因するスタックオーバーフローエラーを回避するために関数をテール再帰的にする方法はありますか? – Panayotis

関連する問題