惯用scala方式实现这种简单的分裂式功能

时间:2012-09-28 19:21:52

标签: scala haskell

我想实现一个具有以下特征的函数:

  • arrayArray[A])和一些pieces作为参数返回(Int
  • 返回arraypieces数组中的array数组。
  • 如果可能的话,所有部分的长度应相等,否则第一部分应该比最后一部分长一个(如果pieces的长度不是split :: [a] -> Int -> [[a]] split list pieces = go list (length list `div` pieces) where go xs n | l > n && m == 0 = take n xs : go (drop n xs) n | l > n = take (n + 1) xs : go (drop (n + 1) xs) n | otherwise = [xs] where l = length xs m = l `mod` n 的倍数)
在Haskell中我会按照这些方式编写一些代码:

Array

虽然在Scala中我遇到很多困难来编写这个(基本)函数。对于递归,if似乎没有适应。然后,允许我实现我在haskell中使用的那种警卫的a结构不允许代替表达式,这对我来说似乎很奇怪。我遇到的另一个问题是我不知道如何使我的scala代码具有多态性(就像我的Haskell代码一样)。最后但并非最不重要的是,我不知道如何制作Array等效的多态,而且还有{{1}}实例,因为Scala中有许多基本集合。

我可以使用完整的解释解决方案或简单的提示来回答我的误解。

1 个答案:

答案 0 :(得分:2)

翻译非常简单。我没有单独调用takedrop,而是使用可能更高效的splitAt。当然,你可以使这个尾递归。而且我还认为“惯用”Scala可能在方法中使用IndexedSeq.newBuilder,这可能再次更有效,但我想这不是你想要的。

请注意,Scala的数组是可变的,因此您需要Vector或更通用的IndexedSeq

import collection.immutable.{IndexedSeq => ISeq}

def split[A](seq: ISeq[A], pieces: Int): ISeq[ISeq[A]] = {
  val n = seq.size / pieces
  def loop(xs: ISeq[A]): ISeq[ISeq[A]] = {   
    val l = xs.size
    if(l > n) {
      val m = l % n
      val (begin, end) = xs.splitAt(if(m == 0) n else n + 1)
      begin +: loop(end)
    } else ISeq(xs)
  }
  loop(seq)
}

split(1 to 20, 3) // correct