【问题标题】:How do I remove an element from a Vector?如何从 Vector 中删除元素?
【发布时间】:2013-02-28 03:28:13
【问题描述】:

这就是我现在正在做的事情:

  private var accounts = Vector.empty[Account]

  def removeAccount(account: Account)
  {
    accounts = accounts.filterNot(_ == account)
  }

有没有更易读的解决方案?理想情况下,我想写accounts = accounts.remove(account)

【问题讨论】:

  • 如果帐户存在两个(或更多)副本,应该怎么办?

标签: scala collections vector immutability trie


【解决方案1】:

如果您不想使用 filterNot 闭包,则可以改用更详细但更明确的 for-comprehension 样式。

private var accounts = Vector.empty[Account]

def removeAccount(account: Account)
{
    accounts = for { a <- accounts
                     if a != account } yield { a }
}

在这种情况下是否感觉更好,这是个人喜好问题。

当然,对于涉及嵌套 flatMap 等的更复杂的表达式,我同意 Martin Odersky 的建议,即 for-comprehensions 可以更容易阅读,尤其是对于新手而言。

【讨论】:

    【解决方案2】:

    你可以这样做:

    def removeFirst[T](xs: Vector[T], x: T) = {
      val i = xs.indexOf(x)
      if (i == -1) xs else xs.patch(i, Nil, 1)
    }
    

    然后

    accounts = removeFirst(accounts, account)
    

    不过,我认为问题的关键在于 Vector 可能不是您想要取出的 set 项的正确集合类型(提示:尝试Set)。如果你想索引一个 ID 或一个插入索引,那么 Map 可能就是你所追求的(它确实有一个 - 方法)。如果你想高效地索引多个事物,你需要一个数据库!

    【讨论】:

      【解决方案3】:

      我会用这个:

      accounts filterNot account.==
      

      这对我来说读起来很好,但是 ymmv。我也想要一个不带谓词的count,但是集合库确实缺乏专门的方法,让有谓词的人可以泛化操作。

      在 2.8.x 之前,有一个 - 方法,由于语义问题,iirc 已被弃用。如果我的记忆对我有用,它实际上可能会在 2.10 恢复,但事实并非如此。 编辑: 我检查了它,发现- 现在保留用于修改它所应用的集合的可变 方法。我会全力支持-:/:-,尽管在序列上,删除第一个或最后一个元素等于某物是有意义的。有人愿意为此买票吗?我会赞成。 :-)

      【讨论】:

        【解决方案4】:

        您可以使用为所有序列定义的diff 方法。它计算两个序列之间的多重集差异 - 这意味着它会根据需要删除尽可能多的元素。

        Vector(1, 2, 1, 3, 2).diff(Seq(1)) => 
        Vector(2, 1, 3, 2)
        
        Vector(1, 2, 1, 3, 2).diff(Seq(1, 1)) =>
        Vector(2, 3, 2)
        
        Vector(1, 2, 1, 3, 2).diff(Seq(1, 1, 2))  
        Vector(3, 2)
        

        【讨论】:

          【解决方案5】:

          不幸的是没有,更糟糕的是(也许),如果同一个帐户出现两次,filterNot 将删除他们两个。我唯一能提供的可读性就是使用

          accounts.filter(_ != account)
          

          另一种可能性是使用具有删除操作的集合类型,例如TreeSet(称为-)。如果您没有重复的条目,Set 完全可以。 (当然,对于某些操作来说它比较慢,但它可能更适合应用程序——它在删除单个条目时更有效;使用filterNot,您基本上必须再次构建整个Vector。)

          【讨论】:

          • 是否有一个不可变的Set 按插入顺序组织元素?
          • scala.collection.mutable.LinkedHashSet
          • TreeSet 可以订购,但您必须自己订购。不过,这很尴尬:您需要知道订购索引才能搜索您的商品。如果它可以是Account 的属性,那么您的状态就很好。否则很难添加,因为你需要知道例如一个 ID 号,以便找到您的项目,但您只有该项目而不是它的 ID。
          • 您可以使用diff 方法删除受控数量的实例