2

Scala 標準ライブラリには、述語を満たすコレクション内のオブジェクトの範囲を取得するメソッドがありません。

def <???>(p: A => Boolean): List[List[A]] = {
  val buf = collection.mutable.ListBuffer[List[A]]()
  var elems = this.dropWhile(e => !p(e))
  while (elems.nonEmpty) {
    buf += elems.takeWhile(p)
    elems = elems.dropWhile(e => !p(e))
  }
  buf.toList
}

そのような方法の良い名前は何ですか? そして、私の実装は十分ですか?

4

4 に答える 4

7

私はchunkWithまたはchunkByに行きます

あなたの実装に関しては、これは再帰を求めていると思います! これに記入できるか確認してください

@tailrec def chunkBy[A](l: List[A], acc: List[List[A]] = Nil)(p: A => Boolean): List[List[A]] = l match {
  case Nil => acc
  case l    =>
    val next = l dropWhile !p
    val (chunk, rest) = next span p
    chunkBy(rest, chunk :: acc)(p)
}

なぜ再帰?アルゴリズムを理解するのがはるかに簡単で、バグがない可能性が高くなります (変数がない場合)。

述語の否定のための構文 !p は、暗黙的な変換によって実現されます

implicit def PredicateW[A](p: A => Boolean) = new {
  def unary_! : A => Boolean = a => !p(a)
}

驚くほど便利なので、私は通常これを手元に置いておきます

于 2012-10-22T05:35:23.487 に答える
2

どうですか:

def chunkBy[K](f: A => K): Map[K, List[List[A]]] = ...

に似てgroupByいますが、連続したチャンクをチャンクとして保持します。これを使えば、xs.chunkBy(p)(true)欲しいものを手に入れることができます。

于 2012-10-22T05:30:22.270 に答える
2

多かれ少なかれそれを行う文字列操作であり、 に似ているsplitWithため、おそらくそれを呼び出したいと思うでしょう。splitsplitAt

ちなみに、これは非常にコンパクトな実装です (ただし、多くの不要な作業を行うため、速度には適していません。あなたの実装は問題ありません)。

def splitWith[A](xs: List[A])(p: A => Boolean) = {
  (xs zip xs.scanLeft(1){ (i,x) => if (p(x) == ((i&1)==1)) i+1 else i }.tail).
  filter(_._2 % 2 == 0).groupBy(_._2).toList.sortBy(_._1).map(_._2.map(_._1))
}
于 2012-10-22T06:05:11.043 に答える
1

oxbowのコードを少し改良するだけで、署名が軽くなります

def chunkBy[A](xs: List[A])(p: A => Boolean): List[List[A]] = {
  @tailrec
  def recurse(todo: List[A], acc: List[List[A]]): List[List[A]] = todo match {
    case Nil => acc
    case _ =>
      val next = todo dropWhile (!p(_))
      val (chunk, rest) = next span p
      recurse(rest, acc ::: List(chunk))
  }
  recurse(xs, Nil)
}
于 2012-10-22T10:50:14.097 に答える