我正在努力解决Scala中缺少Java Iterator.remove()
的问题。特别是,我希望在一个大型可变映射的单个传递中删除满足谓词的元素并将它们收集在另一个可变映射中。
这就是我想要做的事情:
def main(args: Array[String]) {
val map = new TrieMap[String, Integer]();
map += "one" -> 1
map += "two" -> 2
// Remove all elems whose value is > 1 and put them in val removed.
val removed = removeIf(map, _._2 > 1)
}
def removeIf(
map: mutable.Map[String, Integer],
p: ((String, Integer)) => Boolean): mutable.Map[String, Integer] = {
val result = mutable.Map[String, Integer]()
val iter = map.iterator
while (iter.hasNext) {
val elem = iter.next()
if ( p(elem) ) {
iter.remove() // Error
result += elem
}
}
result
}
出于某些合理的原因,Scala的Iterator
即使在可变集合上也没有实现remove()
。
修改 下面提供的两种解决方案是:
不要担心第二次传递的成本,并使用filter()然后--=
删除已过滤的条目:
val result = map.filter(p)
map - = result.keys
使用分区并将新地图重新分配给旧变量:
(result,newMap)= map.partition({case(k,v)=> ...})
答案 0 :(得分:5)
如果您可以返回新的Map对象,则以下情况有效。该解决方案使用partition
集合方法,仅使用一次传递。
scala> val map = TrieMap[String, Integer]("one" -> 1, "two" -> 2)
map: scala.collection.concurrent.TrieMap[String,Integer] = TrieMap(two -> 2, one -> 1)
scala> val (newMap, removed) = map.partition({case(_, x) => x > 1})
newMap: scala.collection.concurrent.TrieMap[String,Integer] = TrieMap(two -> 2)
removed: scala.collection.concurrent.TrieMap[String,Integer] = TrieMap(one -> 1)
答案 1 :(得分:1)
解决此问题的惯用方法是使用filter()
/ def main(args: Array[String]) {
val map = new TrieMap[String, Integer]();
map += "one" -> 1
map += "two" -> 2
val removed = map.filterNot(_._2 > 1)
val newMap = map.filter(_._2 > 1)
}
:
val (newMap, removed) = map.partition(_._2 > 1)
但是,这两个调用可以组合成一个分区调用:
partition()
最重要的是,更新可变集合是将程序习惯用法应用于函数式语言,并为某些类型的错误打开了大门。返回新的,不可变的集合更符合功能上的惯用。
感谢rogue-one呼叫{{1}}作为选项。
答案 2 :(得分:0)
尝试groupBy谓词,你将有一个两个键的映射:对于应该保留的键是true,对于应该删除的键是false。
val p: ((String, Int)) => Boolean = (_._2>1)
private val booleanToStringToInt = Map[String, Int]("one" -> 1, "two" -> 2).groupBy(p)
val remain = booleanToStringToInt(true)
val removed = booleanToStringToInt(false)