2016-12-04 67 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) 
) 

编辑:这里效率更高,尽管不太优雅的尾递归版本。它以相反的方式构建结果列表,因为在列表结尾处调用带索引的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