如何从ListBuffer中删除多个索引(以快速方式)?

时间:2012-07-12 09:28:27

标签: scala

在Scala中有一种很好的方法可以从ListBuffer中删除多个索引(以快速方式)吗?

示例:

val indicesToDelete = List(4, 1)
val buffer = ListBuffer(a, b, c, d, e)

结果:

ListBuffer(b, c, e)

我找不到能够完成这项工作的预定义功能。

可以对索引进行排序并删除以最高索引等开头的元素,因此不会出现复杂情况。但排序需要O(n * log n)。有没有更快的方式(可能是我错过了预先定义的东西)?

UPDATE 1:应在现有的ListBuffer对象中删除元素,不应创建新的ListBuffer对象。

4 个答案:

答案 0 :(得分:6)

您必须使用zipWithIndex,因为其他帖子已经这样做了,否则索引会发生变化,您可能会意外删除错误的项目。但是我会使用foldLeft而不是filtermap + collect,而filter + mapbuffer.zipWithIndex.collect { case (x,i) if !indicesToDelete.contains(i) => x } + for { (x,i) <- buffer.zipWithIndex if !indicesToDelete.contains(i) } yield x 相同,但是只需一步。

{{1}}

这也可以写成

{{1}}

答案 1 :(得分:5)

与其他人不同,我会假设您希望就地进行工作,因为您提到了关于索引重新编号的问题。如果排序是您关心的那么

1)将要删除的索引粘贴到常量时间查找集而不是列表中。根据索引的范围,散列集或位集似乎是合适的。 2)以相反的顺序遍历列表缓冲区,删除要删除的集合中的索引。

scala> val buffer = ListBuffer("a", "b", "c", "d", "e")
buffer: scala.collection.mutable.ListBuffer[java.lang.String] = ListBuffer(a, b, c, d, e)

scala> val indicesToDelete = BitSet(4, 1)
indicesToDelete: scala.collection.mutable.BitSet = BitSet(1, 4)

scala> for (i <- (buffer.size -1) to 0 by -1) if (indicesToDelete contains i) buffer remove i

scala> buffer
res19: scala.collection.mutable.ListBuffer[java.lang.String] = ListBuffer(a, c, d)

请注意,虽然这会删除n log n种索引,但这并不能使其成为线性算法。从类似数组的结构中进行就地删除并不便宜。每次删除都必须向下复制更高的索引。

要获得线性删除索引,您需要做一些更多的事情,您需要1)向前走,根据您目前为止删除的数字向下复制未删除的元素。当你完成后,2)删除前n个元素,其中n是你删除的数字。

scala> val buffer = ListBuffer("a", "b", "c", "d", "e")  
buffer: scala.collection.mutable.ListBuffer[java.lang.String] = ListBuffer(a, b, c, d, e)

scala> val indicesToDelete = BitSet(4, 1)
indicesToDelete: scala.collection.mutable.BitSet = BitSet(1, 4)

scala> var deleted = 0
deleted: Int = 0

scala> for (i <- 0 until buffer.size)
     |    if (indicesToDelete contains i) {
     |       deleted += 1
     |    } else if (deleted > 0) {
     |        buffer(i - deleted) = buffer(i)
     |    }

scala> }

scala> buffer trimEnd deleted

scala> buffer
res0: scala.collection.mutable.ListBuffer[java.lang.String] = ListBuffer(a, c, d)

答案 2 :(得分:3)

怎么样:

buffer.zipWithIndex.filter( p => !(indicesToDelete contains p._2) ).map( _._1 )

O(NM)其中Nbuffer中的数字,M indicesToDelete中的元素数量。

如果您关注效果,可以随时indicesToDelete Set。在这种情况下,性能为O(N):假设{H}集为O(1)摊销,O(NlogM)TreeSet

整理其他海报的所有好主意:

buffer.view.zipWithIndex.collect { case (x,i) if !indicesToDelete.contains(i) => x }

只给你一次通过数据。

答案 3 :(得分:0)

import collection.mutable.ListBuffer

val indicesToDelete = List(4, 1)
val buffer = ListBuffer('a', 'b', 'c', 'd', 'e')

def exclude[T](l:ListBuffer[T], indice: List[Int]) = {
  val set = indice.toSet
  l.zipWithIndex.foldLeft(ListBuffer.empty[T]){ case (c, next) =>
    if(set(next._2+1)) c else c :+ next._1
  } 

}

exclude(buffer, indicesToDelete)