5

Scalaは、不変シーケンスのフィルタリングにおいて非常に洗練されています。

var l = List(1,2,3,4,5,6)
l = l.filter(_%2==1)

しかし、ArrayBufferのような可変コレクションでこれを行うにはどうすればよいですか?私が見つけたのは、単一の要素またはスライスを削除するか、別のシーケンスから要素を削除することだけですが、述語によって指定された要素を削除するものは何もありません。

編集:私はこれに似たものを見つけることを望んでいました:

trait Removable[A] extends Buffer[A]{ 
  def removeIf(p: A => Boolean){
    var it1 = 0
    var it2 = 0

    while(it2 < length){
      if( p( this(it2) ) ){
        it2 += 1;
      } 
      else {
        this(it1) = this(it2)
        it1 += 1;
        it2 += 1;
      }
    }

    trimEnd(it2-it1)
  }
}

これは線形時間でフィルタリングされ、任意のバッファに混在させることができますが、意味があるのはArrayBufferだけです。リストバッファでは、インデックス作成に線形時間がかかるため、処理が遅くなります。

4

6 に答える 6

3

私の推測では、新しいバッファを作成してフィルタリングする方が効率的であるため、通常filterはその結果を使用して使用します。それ以外の場合は、独自のインプレースフィルターメソッドを作成できます。

def filterInPlace[A](b: collection.mutable.Buffer[A])(fun: A => Boolean): Unit = {
  var sz = b.size
  var i = 0; while(i < sz) {
    if (fun(b(i))) {
      i += 1
    } else {
      sz -= 1
      b.remove(i)
    }
  }
}

val b = collection.mutable.ArrayBuffer((1 to 6): _ *)
filterInPlace(b)(_ % 2 == 1)
println(b)
于 2011-04-05T01:39:04.450 に答える
1

突然変異を実行することによって機能する一連のメソッドを持つことについての議論がありましたが、優れた一般的なセットを思い付くのは驚くほど困難であり、その一方で、それに対する十分な需要がありませんでした。

于 2011-04-05T02:10:58.357 に答える
1

と同じようにしArrayBufferます。すべてのコレクションクラスには、使用可能な同じメソッドがあります。

于 2011-04-05T10:21:05.090 に答える
1

私はこれを思いついた

import scala.collection.mutable

trait BufferUtils {
    import BufferUtils._
    implicit def extendMutableBuffer[T](org: mutable.Buffer[T]): ExtendedBuffer[T] = new ExtendedBuffer(org)
}

object BufferUtils extends BufferUtils {

    implicit class ExtendedBuffer[T](val org: mutable.Buffer[T]) extends AnyVal {
        def removeIf(pred: (T) => Boolean): Unit = {
            // target holds the index we want to move the next element to
            var target = 0

            for (i <- org.indices;
                 elem = org(i)
                 if !pred(elem)) {

                org(target) = elem
                target += 1
            }

            org.remove(target, org.size - target)
        }
    }

}
于 2018-01-22T13:14:04.690 に答える
0

これは私にとってはうまくいきましたが、clone()でのみ機能したため、新しいArrayBufferを作成します:-)

scala> import collection.mutable.ArrayBuffer
import collection.mutable.ArrayBuffer

scala> val buf = ArrayBuffer(1,2,3,4,5,6,7,8,9,10)
buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> buf.clone foreach { x => if (x > 4) buf -= x }

scala> buf
res1: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)

しかし、より良い方法は、削除したい要素のみの新しい配列を作成し(したがって、バッファー全体をコピーしない)、次にそれらを削除することです。

scala> val buf = ArrayBuffer(1,2,3,4,5,6,7,8,9,10)
buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> buf filter { _ > 4 } foreach { buf -= _ }

scala> buf
res3: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)
于 2011-04-05T07:17:57.053 に答える
0

多くwithFilterの場合、特にバッファが最終的に不変の構造に変換される場合は、十分です。確かに、実際には要素を削除しませんが、少なくとも新しいArrayBufferオブジェクトは作成しません。

于 2011-04-05T06:25:43.477 に答える