Eu tenho uma lista, que pode conter elementos que serão comparados como iguais. Eu gostaria de uma lista semelhante, mas com um elemento removido. Portanto, de (A, B, C, B, D), gostaria de poder "remover" apenas um B para obter, por exemplo, (A, C, B, D). A ordem dos elementos no resultado não importa.
Eu tenho código de trabalho, escrito de forma inspirada em Lisp em Scala. Existe uma maneira mais idiomática de fazer isso?
O contexto é um jogo de cartas em que dois baralhos de cartas padrão estão em jogo, então pode haver cartas duplicadas, mas ainda jogadas uma de cada 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]
nesta questão é a mão de um jogador?Respostas:
Não vi essa possibilidade nas respostas acima, então:
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 um encanto :-).
fonte
Você pode usar o
filterNot
método.val data = "test" list = List("this", "is", "a", "test") list.filterNot(elm => elm == data)
fonte
Você pode tentar isto:
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)
E como método:
def removeInt(i: Int, li: List[Int]) = { val (left, right) = li.span(_ != i) left ::: right.drop(1) }
fonte
left ::: right.drop(1)
é mais curto do que a instrução if comisEmpty
.tail
em uma lista vazia você recebe uma exceção:scala> List().tail java.lang.UnsupportedOperationException: tail of empty list
.drop(1)
em uma lista vazia, entretanto, retorna uma lista vazia.tail
lança uma exceção se a lista estiver vazia (ou seja, não houverhead
).drop(1)
em uma lista vazia apenas produz outra lista vazia.Infelizmente, a hierarquia de coleções se meteu em uma confusão com o
-
onList
. PoisArrayBuffer
funciona exatamente como você pode esperar:scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2 res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
mas, infelizmente,
List
acabou com umafilterNot
implementação de estilo e, portanto, faz a "coisa errada" e lança um aviso de depreciação para você (bastante sensato, uma vez que está realmente 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)
Portanto, sem dúvida, a coisa mais fácil de fazer é converter
List
em uma coleção que faça isso direito e, em seguida, converter novamente:import collection.mutable.ArrayBuffer._ scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList res2: List[Int] = List(1, 3, 2, 4)
Como alternativa, você pode manter a lógica do código que possui, mas tornar o estilo mais 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)
fonte
removeInt(5,List(1,2,6,4,5,3,6,4,6,5,1))
rendimentosList(4, 6, 2, 1, 3, 6, 4, 6, 5, 1)
. Acho que não era isso que você queria.def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = { assert(listToRemoveFrom.length > idx && idx >= 0) val (left, _ :: right) = listToRemoveFrom.splitAt(idx) left ++ right }
fonte
E se
def removeCard(c: Card, cards: List[Card]) = { val (head, tail) = cards span {c!=} head ::: (tail match { case x :: xs => xs case Nil => Nil }) }
Se você vê
return
, há algo errado.fonte
c
c
, mas apenas primeiro deve ser removido.// 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 }
fonte
Como uma das soluções possíveis, você pode encontrar o índice do primeiro elemento adequado e, em seguida, remover o elemento neste índice:
def removeOne(l: List[Card], c: Card) = l indexOf c match { case -1 => l case n => (l take n) ++ (l drop (n + 1)) }
fonte
span
para fazer a mesma coisa.Apenas outra ideia sobre como fazer isso usando uma dobra:
def remove[A](item : A, lst : List[A]) : List[A] = { lst.:\[List[A]](Nil)((lst, lstItem) => if (lstItem == item) lst else lstItem::lst ) }
fonte
Solução genérica de recursão de cauda:
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) }
fonte
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)
fonte
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) } }
fonte
var
umwhile
loop não é um Scala idiomático.