1

次のような特徴を持つ関数を実装したいのですが。

  • arrayArray[A])といくつかを取り、パラメータとしてpieces()を返しますInt
  • array分割された配列を返しますpieces
  • 可能であれば、すべてのピースの長さを等しくする必要があります。そうでない場合、最初のピースは最後のピースより1要素長くする必要があります(の長さが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それは適応していないようです。そうすると、ifhaskellで使用している種類のガードを実装できる構造は、式の代わりには許可されません。これは私には奇妙に思えます。私が抱えているもう1つの問題は、scalaコードをポリモルフィックにする方法がわからないことです(Haskellコードのように)。最後になりましたが、Scalaには多くの基本的なコレクションがあるためa、同等のポリモーフィックだけでなくインスタンスも作成する方法がわかりません。Array

私は、完全に説明された解決策または私の誤解に答えるための簡単なヒントのいずれかで大丈夫でしょう。

4

1 に答える 1

2

翻訳は非常に簡単です。個別に呼び出す代わりに、takeより効率的な可能性のあるものを使用します。もちろん、この末尾再帰を作成することもできます。また、「慣用的な」Scalaがメソッド内で使用されている可能性があることも主張します。これはおそらく再び効率的ですが、それはあなたが探しているものではないと思います。dropsplitAtIndexedSeq.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 に答える