scala ArrayBuffer 删除带有谓词的所有元素

发布于 2024-10-29 10:48:37 字数 637 浏览 2 评论 0原文

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 有意义,在 ListBuffers 上它会很慢,因为索引确实需要线性时间。

Scala is very elegant in filtering immutable sequences:

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

But how do I do this with a mutable collections like ArrayBuffer?
All I found is the removal of single elements or slices, or remove elements from another sequence, but nothing that removes elements given by a predicate.

Edit:
I was hoping to find something similar tho this:

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

this filters in linear time and can be mixed into any Buffer, but only ArrayBuffer makes sense, on ListBuffers it would be slow, because indexing does take linear time.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

若相惜即相离 2024-11-05 10:48:37

我的猜测是,通过构建新的缓冲区进行过滤会更有效,因此您通常只使用 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)

My guess is that it's more efficient to filter by building a new buffer, so you would normally just use filter and use its result. Otherwise you can write your own in-place filter method:

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)
梦巷 2024-11-05 10:48:37

您可以对 ArrayBuffer 执行相同的操作。所有集合类都具有相同的可用方法。

You do it the same with ArrayBuffer. All collection classes have the same methods available.

单身情人 2024-11-05 10:48:37

人们一直在讨论拥有一组通过执行突变来工作的方法,但想出一套好的通用方法却出人意料地困难,而且另一方面,对此的需求还不够。

There has been discussion about having a set of methods that work by performing mutation, but coming up with a good, generic set is surprisingly hard, and, on the other hand, there just hasn't been enough demand for it.

涫野音 2024-11-05 10:48:37

这对我有用,但只能使用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)

This worked for me, but only with clone(), thus still making a new 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)

But better way would be to make a new array of only those elements, which you want to remove (thus not copying the whole buffer) and then remove them:

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)
晨与橙与城 2024-11-05 10:48:37

我想出了这个

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

}

I came up with this

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

}
没有心的人 2024-11-05 10:48:37

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

Often withFilter is good enough, especially if the Buffer is converted to an immutable structure in the end. True, it doesn't really remove the elements, but at least it doesn't create a new ArrayBuffer object.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文