1

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

  • 将一个array( Array[A]) 和一个pieces要返回的 ( Int) 作为参数
  • 返回array分成pieces几部分的数组。
  • 如果可能,所有部分的长度都应该相等,否则第一个应该比最后一个长一个元素(如果 的长度array不是 的倍数pieces

在 Haskell 中,我会按照这些思路编写一些代码:

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

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

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

4

1 回答 1

2

翻译很直接。我没有单独调用takeand drop,而是使用splitAtwhich 可能更有效。当然,你可以使这个尾递归。而且我还要争辩说,“惯用的” 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
于 2012-09-28T21:42:19.453 回答