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上它会很慢,因为索引确实需要线性时间。
答案 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)