【问题标题】:Idiomatic scala way to implement this simple split-like function实现这个简单的类拆分函数的惯用 scala 方式
【发布时间】:2012-09-28 19:21:52
【问题描述】:

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

  • 将一个array (Array[A]) 和多个pieces 作为参数返回(Int)
  • 返回分割成pieces 块的array 数组。
  • 如果可能,所有片段的长度应该相等,否则第一个片段应该比最后一个片段长一个元素(如果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 中有许多基本集合。

我会接受完整的解释解决方案或简单的提示来回答我的误解。

【问题讨论】:

  • 其实不是。 .grouped(pieces) 将根据需要返回尽可能多的 pieces 长的片段。我希望这个函数返回pieces 件。
  • 它比你想象的更接近。如果有 transpose-alike,那么您可以转置 .grouped(pieces)... 的结果,尽管这不会保留元素的顺序,如果这很重要的话。
  • 将haskell程序改写成scala是不是一个有趣的课程?
  • progfun?那是什么? :p 我只是想在大型项目之前了解大学的 Scala :)

标签: scala haskell


【解决方案1】:

翻译非常简单。我没有分别调用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

【讨论】:

  • 我刚刚完成了一个丑陋的命令式风格的工作版本。感谢您提供我正在寻找的示例:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-07
  • 2013-08-08
  • 2016-10-12
  • 1970-01-01
  • 2016-03-28
  • 2015-02-07
  • 1970-01-01
相关资源
最近更新 更多