scala ArrayBuffer使用谓词删除所有元素

时间:2011-04-05 01:32:48

标签: scala arraybuffer

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)
  }
}

这个过滤器在线性时间内可以混合到任何Buffer中,但只有ArrayBuffer才有意义,在ListBuffers上它会很慢,因为索引确实需要线性时间。

6 个答案:

答案 0 :(得分: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)

答案 1 :(得分:1)

一直在讨论如何通过执行变异来实现一组方法,但是提出一个好的通用集非常困难,而另一方面,对它的需求还不够。

答案 2 :(得分:1)

您使用ArrayBuffer执行相同的操作。所有集合类都有相同的方法。

答案 3 :(得分: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)
        }
    }

}

答案 4 :(得分:0)

通常withFilter足够好,特别是如果Buffer最终转换为不可变结构。没错,它并没有真正删除元素,但至少它不会创建一个新的ArrayBuffer对象。

答案 5 :(得分: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)