首页 文章

什么是从不可变列表中“删除”一个元素的惯用Scala方法?

提问于
浏览
73

我有一个List,它可能包含比较相等的元素 . 我想要一个类似的List,但删除了一个元素 . 所以从(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)
}

12 回答

  • 2

    我在上面的答案中没有看到这种可能性,所以:

    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)
    

    喜欢魅力:-) .

  • 0

    您可以使用filterNot方法 .

    val data = "test"
    list = List("this", "is", "a", "test")
    list.filterNot(elm => elm == data)
    
  • 8

    你可以试试这个:

    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)
    }
    
  • 30

    不幸的是,集合层次结构在 List 上与 - 陷入了混乱 . 对于 ArrayBuffer ,它的工作方式与您希望的一样:

    scala> collection.mutable.ArrayBuffer(1,2,3,2,4) - 2
    res0: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer(1, 3, 2, 4)
    

    但是,遗憾的是, List 结束了 filterNot 风格的实现,因此"wrong thing"并向你发出了弃用警告(足够明智,因为它实际上是 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)
    

    所以可以说最容易做的就是将 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)
    
  • -3
    def removeAtIdx[T](idx: Int, listToRemoveFrom: List[T]): List[T] = {
        assert(listToRemoveFrom.length > idx && idx >= 0)
        val (left, _ :: right) = listToRemoveFrom.splitAt(idx)
        left ++ right
     }
    
  • 1
    // 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
    }
    
  • 0

    作为一种可能的解决方案,您可以找到第一个合适元素的索引,然后删除此索引处的元素:

    def removeOne(l: List[Card], c: Card) = l indexOf c match {
        case -1 => l
        case n => (l take n) ++ (l drop (n + 1))
    }
    
  • -3

    怎么样

    def removeCard(c: Card, cards: List[Card]) = {
      val (head, tail) = cards span {c!=}   
      head ::: 
      (tail match {
        case x :: xs => xs
        case Nil => Nil
      })
    }
    

    如果你看到 return ,那就有问题了 .

  • 15

    关于如何使用折叠这样做的另一个想法:

    def remove[A](item : A, lst : List[A]) : List[A] = {
        lst.:\[List[A]](Nil)((lst, lstItem) => 
           if (lstItem == item) lst else lstItem::lst )
    }
    
  • 1

    通用尾递归解决方案:

    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)
      }
    
  • 129
    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)
    
  • 4
    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)
    
        }
    
    }
    

相关问题