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, de (A, B, C, B, D) me gustaría poder "eliminar" solo una B para obtener, por ejemplo, (A, C, B, D). No importa el orden de los elementos en el resultado.
Tengo código de trabajo, escrito en una forma inspirada en Lisp en Scala. ¿Hay alguna forma más idiomática de hacer esto?
El contexto es un juego de cartas en el que están en juego dos mazos de cartas estándar, por lo que puede haber cartas duplicadas, pero aún así se juegan una a la 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)
}
List[Card]
en esta pregunta es la mano de un jugador?Respuestas:
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 :-).
fuente
Podrías usar el
filterNot
método.val data = "test" list = List("this", "is", "a", "test") list.filterNot(elm => elm == data)
fuente
Puedes probar 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) }
fuente
left ::: right.drop(1)
es más corto que la declaración if conisEmpty
.tail
en una lista vacía se obtiene una excepción:scala> List().tail java.lang.UnsupportedOperationException: tail of empty list
.drop(1)
en una lista vacía, sin embargo, devuelve una lista vacía.tail
lanza una excepción si la lista está vacía (es decir, no hayhead
).drop(1)
en una lista vacía solo produce otra lista vacía.Por desgracia, la jerarquía de colecciones tiene en sí en un poco de un desastre con
-
elList
. PorqueArrayBuffer
funciona tal como esperas: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 unafilterNot
implementación de estilo y, por lo tanto, hace "lo incorrecto" y le arroja una advertencia de desaprobación (lo suficientemente sensible, ya que en realidad está funcionandofilterNot
):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)
Entonces, posiblemente, lo más fácil de hacer es convertir
List
en una colección que lo haga bien y luego volver a convertir:import collection.mutable.ArrayBuffer._ scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList res2: List[Int] = List(1, 3, 2, 4)
Alternativamente, puede mantener la lógica del código que tiene pero hacer que el estilo sea 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)
fuente
removeInt(5,List(1,2,6,4,5,3,6,4,6,5,1))
rendimientosList(4, 6, 2, 1, 3, 6, 4, 6, 5, 1)
. Creo que esto no es lo que querías.def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = { assert(listToRemoveFrom.length > idx && idx >= 0) val (left, _ :: right) = listToRemoveFrom.splitAt(idx) left ++ right }
fuente
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 ve
return
, algo anda mal.fuente
c
c
, pero solo se debe eliminar la primera.// 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 }
fuente
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)) }
fuente
span
para hacer lo mismo.Solo otro pensamiento sobre cómo hacer esto usando un pliegue:
def remove[A](item : A, lst : List[A]) : List[A] = { lst.:\[List[A]](Nil)((lst, lstItem) => if (lstItem == item) lst else lstItem::lst ) }
fuente
Solución genérica de recursividad de cola:
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) }
fuente
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)
fuente
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) } }
fuente
var
sy unwhile
bucle no es un lenguaje idiomático de Scala.