J'ai une liste, qui peut contenir des éléments comparables. Je voudrais une liste similaire, mais avec un élément supprimé. Donc, de (A, B, C, B, D), j'aimerais pouvoir "supprimer" un seul B pour obtenir, par exemple, (A, C, B, D). L'ordre des éléments dans le résultat n'a pas d'importance.
J'ai un code de travail, écrit de manière inspirée du LISP dans Scala. Y a-t-il un moyen plus idiomatiquede faire cela?
Le contexte est un jeu de cartes dans lequel deux jeux de cartes standard sont en jeu. Il est donc possible que les cartes soient dupliquées mais jouées une par une.
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)
}
Je n'ai pas vu cette possibilité dans les réponses ci-dessus, alors:
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)
Modifier:
scala> remove(2,List(2,2,2))
res0: List[Int] = List(2, 2)
Comme un charme :-).
Vous pouvez utiliser la méthode filterNot.
val data = "test"
list = List("this", "is", "a", "test")
list.filterNot(Elm => Elm == data)
Vous pouvez essayer ceci:
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)
Et comme méthode:
def removeInt(i: Int, li: List[Int]) = {
val (left, right) = li.span(_ != i)
left ::: right.drop(1)
}
Malheureusement, la hiérarchie des collections s'est retrouvée dans le pétrin avec -
sur List
. Pour ArrayBuffer
, cela fonctionne exactement comme vous le souhaiteriez:
scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
mais, malheureusement, List
a abouti à une implémentation de style filterNot
- et fait donc la "mauvaise chose" et vous lance un avertissement de dépréciation (assez raisonnable, puisqu'il s'agit en fait de 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)
Donc, la chose la plus simple à faire est sans doute de convertir List
en une collection qui fonctionne correctement, puis de reconvertir:
import collection.mutable.ArrayBuffer._
scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList
res2: List[Int] = List(1, 3, 2, 4)
Alternativement, vous pouvez garder la logique du code que vous avez mais rendre le style plus idiomatique:
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)
def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = {
assert(listToRemoveFrom.length > idx && idx >= 0)
val (left, _ :: right) = listToRemoveFrom.splitAt(idx)
left ++ right
}
// 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
}
En tant que solution possible, vous pouvez rechercher un index du premier élément approprié, puis supprimer un élément à cet index:
def removeOne(l: List[Card], c: Card) = l indexOf c match {
case -1 => l
case n => (l take n) ++ (l drop (n + 1))
}
Que diriez-vous
def removeCard(c: Card, cards: List[Card]) = {
val (head, tail) = cards span {c!=}
head :::
(tail match {
case x :: xs => xs
case Nil => Nil
})
}
Si vous voyez return
, il y a quelque chose qui ne va pas.
Juste une autre pensée sur la façon de faire cela en utilisant un pli:
def remove[A](item : A, lst : List[A]) : List[A] = {
lst.:\[List[A]](Nil)((lst, lstItem) =>
if (lstItem == item) lst else lstItem::lst )
}
Solution générique de récursion de queue:
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)
}