empty - ¿Cuál es una manera idiomática de Scala de "eliminar" un elemento de una lista inmutable?
scala listbuffer add (12)
Como una posible solución, puede encontrar el índice del primer elemento adecuado y luego eliminar el elemento en este índice:
def removeOne(l: List[Card], c: Card) = l indexOf c match {
case -1 => l
case n => (l take n) ++ (l drop (n + 1))
}
Tengo una lista, que puede contener elementos que se compararán como iguales. Me gustaría una Lista similar, pero con un elemento eliminado. Entonces desde (A, B, C, B, D) me gustaría poder "eliminar" solo una B para obtener, por ejemplo, (A, C, B, D). El orden de los elementos en el resultado no importa.
Tengo un código de trabajo, escrito en una forma inspirada en Lisp en Scala. ¿Hay una manera más idiomática de hacer esto?
El contexto es un juego de cartas en el que dos mazos de cartas estándar están en juego, por lo que puede haber cartas duplicadas, pero todavía se juegan de a una por vez.
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)
}
Desafortunadamente, la jerarquía de colecciones se metió en un lío con -
en la List
. Para ArrayBuffer
funciona igual que lo que podría esperar:
scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2
res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
pero, lamentablemente, List
terminó con una implementación filterNot
- filterNot
y, por lo tanto, hace lo "incorrecto" y lanza una advertencia de desaprobación (lo suficientemente sensible, ya que en realidad no filterNot
):
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)
Así que podría decirse que lo más fácil es convertir List
en una colección que hace esto bien, y luego convertir de nuevo:
import collection.mutable.ArrayBuffer._
scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList
res2: List[Int] = List(1, 3, 2, 4)
Alternativamente, puedes mantener la lógica del código que tienes pero hacer el estilo más idiomático:
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)
No he visto esta posibilidad en las respuestas anteriores, entonces:
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)
Editar:
scala> remove(2,List(2,2,2))
res0: List[Int] = List(2, 2)
Como un encanto :-).
Podría usar el método filterNot.
val data = "test"
list = List("this", "is", "a", "test")
list.filterNot(elm => elm == data)
Puedes intentar esto:
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)
Y como método:
def removeInt(i: Int, li: List[Int]) = {
val (left, right) = li.span(_ != i)
left ::: right.drop(1)
}
Qué tal si
def removeCard(c: Card, cards: List[Card]) = {
val (head, tail) = cards span {c!=}
head :::
(tail match {
case x :: xs => xs
case Nil => Nil
})
}
Si ves el return
, hay algo mal.
Solo otro pensamiento sobre cómo hacer esto usando un doblez:
def remove[A](item : A, lst : List[A]) : List[A] = {
lst.:/[List[A]](Nil)((lst, lstItem) =>
if (lstItem == item) lst else lstItem::lst )
}
Solución de recurrencia de cola genérica:
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)
}
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
}
object HelloWorld {
def main(args: Array[String]) {
var months: List[String] = List("December","November","October","September","August", "July","June","May","April","March","February","January")
println("Deleting the reverse list one by one")
var i = 0
while (i < (months.length)){
println("Deleting "+months.apply(i))
months = (months.drop(1))
}
println(months)
}
}
val list : Array[Int] = Array(6, 5, 3, 1, 8, 7, 2)
val test2 = list.splitAt(list.length / 2)._2
val res = test2.patch(1, Nil, 1)