1
リストを特定の数のチャンクに分割する最も簡単な方法は何ですか?チャンクサイズはランダムにしたいが、すべてのチャンクには少なくとも1つの要素を入れることが望ましい。リストを一定数のランダムサイズのサブリストに分割する
リストを特定の数のチャンクに分割する最も簡単な方法は何ですか?チャンクサイズはランダムにしたいが、すべてのチャンクには少なくとも1つの要素を入れることが望ましい。リストを一定数のランダムサイズのサブリストに分割する
それがこれを行うための最も簡単な方法だ場合、私は知らないが、私はそのようなことは、かなり良いディストリビューションで動作するはずだと思う:
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
}
adamwy大きな入力に起因するスタックオーバーフローエラーを回避するために関数をテール再帰的にする方法はありますか? – Panayotis