У меня есть список, который может содержать элементы, которые будут сравниваться как равные. Мне нужен аналогичный список, но с удалением одного элемента. Итак, из (A, B, C, B, D) я хотел бы иметь возможность «удалить» только один B, чтобы получить, например, (A, C, B, D). Порядок элементов в результате не имеет значения.
У меня есть рабочий код, написанный на Scala в стиле Lisp. Есть ли более идиоматический способ сделать это?
Контекст - это карточная игра, в которой участвуют две колоды стандартных карт, поэтому могут быть дубликаты карт, но все равно играть по одной.
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]
в этом вопросе рука игрока?Ответы:
Я не видел такой возможности в ответах выше, поэтому:
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)
Редактировать:
scala> remove(2,List(2,2,2)) res0: List[Int] = List(2, 2)
Как колдовство :-).
источник
Вы можете использовать этот
filterNot
метод.val data = "test" list = List("this", "is", "a", "test") list.filterNot(elm => elm == data)
источник
Вы можете попробовать это:
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)
И как метод:
def removeInt(i: Int, li: List[Int]) = { val (left, right) = li.span(_ != i) left ::: right.drop(1) }
источник
left ::: right.drop(1)
он короче, чем оператор if сisEmpty
.tail
на пустой список вы получите исключение:scala> List().tail java.lang.UnsupportedOperationException: tail of empty list
.drop(1)
однако в пустом списке возвращает пустой список.tail
выдает исключение, если список пуст (т.е. его нетhead
).drop(1)
в пустом списке просто дает еще один пустой список.К сожалению, иерархия коллекций немного запуталась из-за
-
onList
. Потому чтоArrayBuffer
это работает так, как вы могли бы надеяться:scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2 res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
но, к сожалению,
List
закончилсяfilterNot
реализацией -стилем и, таким образом, делает "неправильную вещь" и выдает вам предупреждение об устаревании (достаточно разумно, поскольку это действительно так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)
Так что, возможно, проще всего преобразовать
List
в коллекцию, которая делает это правильно, а затем снова преобразовать:import collection.mutable.ArrayBuffer._ scala> ((ArrayBuffer() ++ List(1,2,3,2,4)) - 2).toList res2: List[Int] = List(1, 3, 2, 4)
Как вариант, вы можете сохранить логику кода, который у вас есть, но сделать стиль более идиоматическим:
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)
источник
removeInt(5,List(1,2,6,4,5,3,6,4,6,5,1))
урожайностьList(4, 6, 2, 1, 3, 6, 4, 6, 5, 1)
. Я думаю, это не то, что вы хотели.def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = { assert(listToRemoveFrom.length > idx && idx >= 0) val (left, _ :: right) = listToRemoveFrom.splitAt(idx) left ++ right }
источник
Как насчет
def removeCard(c: Card, cards: List[Card]) = { val (head, tail) = cards span {c!=} head ::: (tail match { case x :: xs => xs case Nil => Nil }) }
Если видите
return
, что-то не так.источник
c
c
, но только сначала следует удалить.// 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 }
источник
В качестве одного из возможных решений вы можете найти индекс первого подходящего элемента, а затем удалить элемент по этому индексу:
def removeOne(l: List[Card], c: Card) = l indexOf c match { case -1 => l case n => (l take n) ++ (l drop (n + 1)) }
источник
span
то же самое.Еще одна мысль о том, как это сделать с помощью складки:
def remove[A](item : A, lst : List[A]) : List[A] = { lst.:\[List[A]](Nil)((lst, lstItem) => if (lstItem == item) lst else lstItem::lst ) }
источник
Общее решение для рекурсии хвоста:
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) }
источник
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)
источник
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) } }
источник
var
с иwhile
цикла - это не идиоматика Scala.