list 从不可变列表中“删除”一个元素的惯用 Scala 方法是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5636717/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is an idiomatic Scala way to "remove" one element from an immutable List?
提问by Gavilan Comun
I have a List, which may contain elements that will compare as equal. I would like a similar List, but with one element removed. So from (A, B, C, B, D) I would like to be able to "remove" just one B to get e.g. (A, C, B, D). The order of the elements in the result does not matter.
我有一个列表,其中可能包含比较相等的元素。我想要一个类似的列表,但删除了一个元素。因此,从 (A, B, C, B, D) 我希望能够“删除”一个 B 以获得例如 (A, C, B, D)。结果中元素的顺序无关紧要。
I have working code, written in a Lisp-inspired way in Scala. Is there a more idiomatic way to do this?
我有工作代码,在 Scala 中以受 Lisp 启发的方式编写。有没有更惯用的方法来做到这一点?
The context is a card game where two decks of standard cards are in play, so there may be duplicate cards but still played one at a time.
上下文是一种纸牌游戏,其中正在播放两副标准纸牌,因此可能会有重复的纸牌,但仍然一次玩一张。
def removeOne(c: Card, left: List[Card], right: List[Card]): List[Card] = {
if (Nil == right) {
return left
}
if (c == right.head) {
return left ::: right.tail
}
return removeOne(c, right.head :: left, right.tail)
}
def removeCard(c: Card, cards: List[Card]): List[Card] = {
return removeOne(c, Nil, cards)
}
回答by Antonin Brettsnajdr
I haven't seen this possibility in the answers above, so:
我在上面的答案中没有看到这种可能性,所以:
scala> def remove(num: Int, list: List[Int]) = list diff List(num)
remove: (num: Int,list: List[Int])List[Int]
scala> remove(2,List(1,2,3,4,5))
res2: List[Int] = List(1, 3, 4, 5)
Edit:
编辑:
scala> remove(2,List(2,2,2))
res0: List[Int] = List(2, 2)
Like a charm :-).
就像一个魅力:-)。
回答by S?ren Mathiasen
You could use the filterNot
method.
你可以用这个filterNot
方法。
val data = "test"
list = List("this", "is", "a", "test")
list.filterNot(elm => elm == data)
回答by Frank S. Thomas
You could try this:
你可以试试这个:
scala> val (left,right) = List(1,2,3,2,4).span(_ != 2)
left: List[Int] = List(1)
right: List[Int] = List(2, 3, 2, 4)
scala> left ::: right.tail
res7: List[Int] = List(1, 3, 2, 4)
And as method:
作为方法:
def removeInt(i: Int, li: List[Int]) = {
val (left, right) = li.span(_ != i)
left ::: right.drop(1)
}
回答by Rex Kerr
Unfortunately, the collections hierarchy got itself into a bit of a mess with -
on List
. For ArrayBuffer
it works just like you might hope:
不幸的是,集合层次结构在-
on 上有点混乱List
。因为ArrayBuffer
它就像您希望的那样工作:
scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
but, sadly, List
ended up with a filterNot
-style implementation and thus does the "wrong thing" andthrows a deprecation warning at you (sensible enough, since it is actually filterNot
ing):
但是,遗憾的是,List
最终得到了一个filterNot
-style 实现,因此做了“错误的事情”并向您发出了弃用警告(足够明智,因为它实际上是filterNot
ing):
scala> List(1,2,3,2,4) - 2
warning: there were deprecation warnings; re-run with -deprecation for details
res1: List[Int] = List(1, 3, 4)
So arguably the easiest thing to do is convert List
into a collection that does this right, and then convert back again:
因此,可以说最简单的方法是转换List
为一个正确执行此操作的集合,然后再次转换回来:
import collection.mutable.ArrayBuffer._
scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList
res2: List[Int] = List(1, 3, 2, 4)
Alternatively, you could keep the logic of the code you've got but make the style more idiomatic:
或者,您可以保留现有代码的逻辑,但使样式更加惯用:
def removeInt(i: Int, li: List[Int]) = {
def removeOne(i: Int, left: List[Int], right: List[Int]): List[Int] = right match {
case r :: rest =>
if (r == i) left.reverse ::: rest
else removeOne(i, r :: left, rest)
case Nil => left.reverse
}
removeOne(i, Nil, li)
}
scala> removeInt(2, List(1,2,3,2,4))
res3: List[Int] = List(1, 3, 2, 4)
回答by Suat KARAKUSOGLU
def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = {
assert(listToRemoveFrom.length > idx && idx >= 0)
val (left, _ :: right) = listToRemoveFrom.splitAt(idx)
left ++ right
}
回答by Ken Bloom
// throws a MatchError exception if i isn't found in li
def remove[A](i:A, li:List[A]) = {
val (head,_::tail) = li.span(i != _)
head ::: tail
}
回答by tenshi
As one possible solutions you can find index of the first suitable element and then remove element at this index:
作为一种可能的解决方案,您可以找到第一个合适元素的索引,然后在该索引处删除元素:
def removeOne(l: List[Card], c: Card) = l indexOf c match {
case -1 => l
case n => (l take n) ++ (l drop (n + 1))
}
回答by Eugene Yokota
How about
怎么样
def removeCard(c: Card, cards: List[Card]) = {
val (head, tail) = cards span {c!=}
head :::
(tail match {
case x :: xs => xs
case Nil => Nil
})
}
If you see return
, there's something wrong.
如果你看到了return
,那就有问题了。
回答by Shankar Shastri
Generic Tail Recursion Solution:
通用尾递归解决方案:
def removeElement[T](list: List[T], ele: T): List[T] = {
@tailrec
def removeElementHelper(list: List[T],
accumList: List[T] = List[T]()): List[T] = {
if (list.length == 1) {
if (list.head == ele) accumList.reverse
else accumList.reverse ::: list
} else {
list match {
case head :: tail if (head != ele) =>
removeElementHelper(tail, head :: accumList)
case head :: tail if (head == ele) => (accumList.reverse ::: tail)
case _ => accumList
}
}
}
removeElementHelper(list)
}
回答by gdiz
Just another thought on how to do this using a fold:
关于如何使用折叠来做到这一点的另一个想法:
def remove[A](item : A, lst : List[A]) : List[A] = {
lst.:\[List[A]](Nil)((lst, lstItem) =>
if (lstItem == item) lst else lstItem::lst )
}