在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对象。
答案 0 :(得分:6)
您必须使用zipWithIndex
,因为其他帖子已经这样做了,否则索引会发生变化,您可能会意外删除错误的项目。但是我会使用foldLeft
而不是filter
或map
+ collect
,而filter
+ map
与buffer.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)
其中N
是buffer
中的数字,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)