如何从Scala的列表中删除对象的首次出现? [英] How should I remove the first occurrence of an object from a list in Scala?
问题描述
从Scala中的列表中删除第一次出现的对象的最佳方法是什么?
What is the best way to remove the first occurrence of an object from a list in Scala?
Coming from Java, I'm accustomed to having a List.remove(Object o)
method that removes the first occurrence of an element from a list. Now that I'm working in Scala, I would expect the method to return a new immutable List
instead of mutating a given list. I might also expect the remove()
method to take a predicate instead of an object. Taken together, I would expect to find a method like this:
/**
* Removes the first element of the given list that matches the given
* predicate, if any. To remove a specific object <code>x</code> from
* the list, use <code>(_ == x)</code> as the predicate.
*
* @param toRemove
* a predicate indicating which element to remove
* @return a new list with the selected object removed, or the same
* list if no objects satisfy the given predicate
*/
def removeFirst(toRemove: E => Boolean): List[E]
当然,我可以通过几种不同的方式自己实现此方法,但是显然没有最好的选择.我不希望将列表转换为Java列表(甚至不转换为Scala可变列表),然后再返回,尽管那肯定可以.我可以使用List.indexWhere(p: (A) ⇒ Boolean)
:
Of course, I can implement this method myself several different ways, but none of them jump out at me as being obviously the best. I would rather not convert my list to a Java list (or even to a Scala mutable list) and back again, although that would certainly work. I could use List.indexWhere(p: (A) ⇒ Boolean)
:
def removeFirst[E](list: List[E], toRemove: (E) => Boolean): List[E] = {
val i = list.indexWhere(toRemove)
if (i == -1)
list
else
list.slice(0, i) ++ list.slice(i+1, list.size)
}
但是,将索引与链表一起使用通常不是最有效的方法.
However, using indices with linked lists is usually not the most efficient way to go.
我可以编写这样一个更有效的方法:
I can write a more efficient method like this:
def removeFirst[T](list: List[T], toRemove: (T) => Boolean): List[T] = {
def search(toProcess: List[T], processed: List[T]): List[T] =
toProcess match {
case Nil => list
case head :: tail =>
if (toRemove(head))
processed.reverse ++ tail
else
search(tail, head :: processed)
}
search(list, Nil)
}
仍然,这并不十分简洁.似乎很奇怪,没有一种可以让我高效而简洁地执行此操作的方法.那么,我是否缺少某些东西,还是我的最后一个解决方案真的很完善?
Still, that's not exactly succinct. It seems strange that there's not an existing method that would let me do this efficiently and succinctly. So, am I missing something, or is my last solution really as good as it gets?
推荐答案
您可以使用span
稍微清理一下代码.
You can clean up the code a bit with span
.
scala> def removeFirst[T](list: List[T])(pred: (T) => Boolean): List[T] = {
| val (before, atAndAfter) = list span (x => !pred(x))
| before ::: atAndAfter.drop(1)
| }
removeFirst: [T](list: List[T])(pred: T => Boolean)List[T]
scala> removeFirst(List(1, 2, 3, 4, 3, 4)) { _ == 3 }
res1: List[Int] = List(1, 2, 4, 3, 4)
Scala Collections API概述是了解某些内容的好地方鲜为人知的方法.
The Scala Collections API overview is a great place to learn about some of the lesser known methods.
这篇关于如何从Scala的列表中删除对象的首次出现?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!