问题
This is what I'm doing now:
private var accounts = Vector.empty[Account]
def removeAccount(account: Account)
{
accounts = accounts.filterNot(_ == account)
}
Is there a more readable solution? Ideally, I'd like to write accounts = accounts.remove(account)
.
回答1:
I'd use this:
accounts filterNot account.==
Which reads pretty well to me, but ymmv. I'd also like a count
that doesn't take a predicate, but the collection library is really lacking in specialized methods where one with a predicate can generalize the operation.
Until 2.8.x, there was a -
method, which got deprecated, iirc, because of semantic issues. It could actually have come back on 2.10 if my memory is serving me right, but it didn't. Edit: I checked it out, and saw that -
is now reserved for a mutable method that modifies the collection it is applied on. I'd be all in favor of -:
/:-
though on sequences, where it makes sense to drop the first or last element equal to something. Anyone willing to front a ticket for that? I'd upvote it. :-)
回答2:
There unfortunately is not, and worse still (perhaps), if the same account is present twice, filterNot
will remove both of them. The only thing I can offer for readability is to use
accounts.filter(_ != account)
Another possibility is to use a collection type that does have a remove operation, such as a TreeSet
(where it is called -
). If you don't have duplicate entries anyway, a Set
is perfectly okay. (It is slower for some operations, of course, but it probably is a better fit to the application--it's more efficient at removing individual entries; with a filterNot
you basically have to build the entire Vector
again.)
回答3:
You could do something like this:
def removeFirst[T](xs: Vector[T], x: T) = {
val i = xs.indexOf(x)
if (i == -1) xs else xs.patch(i, Nil, 1)
}
then
accounts = removeFirst(accounts, account)
I think the nub of the problem, though, is that a Vector
probably isn't the right collection type for a set of items where you want to pull things out (hint: try Set
). If you want to index on an ID or an insertion index then Map
could be what you're after (which does have a -
method). If you want to index on multiple things efficiently, you need a database!
回答4:
You can use the diff
method which is defined for all sequences. It computes the multiset difference between two sequences - meaning it will remove as many occurrences of an element as you need.
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:
If you prefer not to use the filterNot
closure, you could use the more verbose yet more explicit for-comprehension style instead.
private var accounts = Vector.empty[Account]
def removeAccount(account: Account)
{
accounts = for { a <- accounts
if a != account } yield { a }
}
It's a matter of personal preference whether this is felt to be better in this case.
Certainly for more complex expressions involving nested flatMaps etc, I agree with Martin Odersky's advice that for-comprehensions can be quite a bit easier to read, especially for novices.
来源:https://stackoverflow.com/questions/15364252/how-do-i-remove-an-element-from-a-vector