2013-03-12 96 views
1

这是我现在在做什么:如何从Vector中删除元素?

private var accounts = Vector.empty[Account] 

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

是否有一个更可读的解决方案吗?理想情况下,我想写accounts = accounts.remove(account)

+1

如果账户存在两个(或更多)副本,会发生什么? – paradigmatic 2013-03-12 16:58:31

回答

3

我会使用这样的:

accounts filterNot account.== 

其内容颇能我,但情况因人而异。我还想要一个不带谓词的count,但收集库实际上缺乏专门的方法,其中有谓词的人可以推广这个操作。

直到2.8.x,出现 a -方法,由于语义问题,它被弃用,iirc。如果我的记忆正在为我服务,它实际上可能会在2.10时回来,但事实并非如此。 编辑:我检查出来,看到-现在保留为可变方法,修改它应用的集合。尽管在序列上,我会全都赞成-:/:-,在这种情况下,将第一个或最后一个元素放在某个位置是合理的。任何人都愿意为此付票吗?我会赞成它。 :-)

4

不幸的是,如果同一帐户存在两次,filterNot将删除它们两个,但更糟的是(可能)。我可以提供可读性的唯一的事情就是用

accounts.filter(_ != account) 

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

+0

是否有一个不可变的'Set'按照它们插入的顺序来组织元素? – fredoverflow 2013-03-12 14:57:51

+1

有'scala.collection.mutable.LinkedHashSet'。 – 2013-03-12 15:06:08

+0

可以订购'TreeSet',但您必须提供自己的订购。但事实证明这很尴尬:您需要知道订购索引才能搜索您的物品。如果它可以成为“账户”的属性,那么您的状态良好。否则很难添加,因为你需要知道例如一个ID号码为了找到你的物品,但你只有物品不是它的ID。 – 2013-03-12 15:12:08

3

您可以使用为所有序列定义的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) 
3

你可以做这样的事情:

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)。如果你想索引一个ID或插入索引,那么Map可能就是你之后(它有一个-方法)。如果你想有效地索引多个东西,你需要一个数据库!

0

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

private var accounts = Vector.empty[Account] 

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

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

当然,对于涉及嵌套flatMaps等的更复杂表达式,我同意Martin Odersky的建议,即理解可以更容易阅读,特别是对于新手。