删除“第一个”集合中的对象
在某些情况下,我需要逐出 Java Set
中最旧的元素。该集合是使用 LinkedHashSet
,这使得这很简单:只需删除集合迭代器返回的第一个元素:
Set<Foo> mySet = new LinkedHashSet<Foo>();
// do stuff...
if (mySet.size() >= MAX_SET_SIZE)
{
Iterator<Foo> iter = mySet.iterator();
iter.next();
iter.remove();
}
这很丑陋:如果我使用的话,需要 3 行代码来完成我可以用 1 行代码完成的事情SortedSet
(由于其他原因,SortedSet
在这里不是一个选项):
if (/*stuff*/)
{
mySet.remove(mySet.first());
}
那么有没有一种更简洁的方法来执行此操作,无需:
- 更改
Set
实现,还是 - 编写静态实用方法?
任何利用 Guava 的解决方案都可以。
我完全意识到集合没有固有的顺序。我询问如何删除迭代顺序定义的第一个条目。
Under certain situations, I need to evict the oldest element in a Java Set
. The set is implemented using a LinkedHashSet
, which makes this simple: just get rid of the first element returned by the set's iterator:
Set<Foo> mySet = new LinkedHashSet<Foo>();
// do stuff...
if (mySet.size() >= MAX_SET_SIZE)
{
Iterator<Foo> iter = mySet.iterator();
iter.next();
iter.remove();
}
This is ugly: 3 lines to do something I could do with 1 line if I was using a SortedSet
(for other reasons, a SortedSet
is not an option here):
if (/*stuff*/)
{
mySet.remove(mySet.first());
}
So is there a cleaner way of doing this, without:
- changing the
Set
implementation, or - writing a static utility method?
Any solutions leveraging Guava are fine.
I am fully aware that sets do not have inherent ordering. I'm asking about removing the first entry as defined by iteration order.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
LinkedHashSet 是 LinkedHashMap 的包装器,它支持简单的“删除最旧的”策略。要将其用作集合,您可以执行以下操作
LinkedHashSet is a wrapper for LinkedHashMap which supports a simple "remove oldest" policy. To use it as a Set you can do
好像不到3行。
当然,如果您的集合由多个线程共享,您必须围绕它进行同步。
seems to be less than 3 lines.
You have to synchronize around it of course if your set is shared by multiple threads.
如果您确实需要在代码中的多个位置执行此操作,只需编写一个静态方法即可。
提出的其他解决方案通常速度较慢,因为它们意味着调用
Set.remove(Object)
方法而不是Iterator.remove()
方法。If you really need to do this at several places in your code, just write a static method.
The other solutions proposed are often slower since they imply calling the
Set.remove(Object)
method instead of theIterator.remove()
method.对于番石榴:
我还会建议一种替代方法。是的,它改变了实现,但不是很大:扩展
LinkedHashSet
并在add
方法中满足该条件:它仍然是 5 行,但对于下面的代码是不可见的使用它。由于这实际上是集合的特定行为,因此将其包含在集合中是合乎逻辑的。
With guava:
I will also suggest an alternative approach. Yes, it it changing the implementation, but not drastically: extend
LinkedHashSet
and have that condition in theadd
method:It's still 5 line, but it is invisible to the code that's using it. And since this is actually a specific behaviour of the set, it is logical to have it within the set.
我认为你这样做的方式很好。这是您经常做的事情,值得寻找更短的方法吗?您可以使用 Guava 做基本相同的事情,如下所示:
这增加了包装集合及其迭代器以进行限制的小开销,然后调用
alwaysTrue()
谓词一次......似乎并不特别不过对我来说值得。编辑:要将我在评论中所说的内容放入答案中,您可以创建一个
SetMultimap
来自动限制每个键可以拥有的值的数量,如下所示:I think the way you're doing it is fine. Is this something you do often enough to be worth finding a shorter way? You could do basically the same thing with Guava like this:
That adds the small overhead of wrapping the set and its iterator for limiting and then calling the
alwaysTrue()
predicate once... doesn't seem especially worth it to me though.Edit: To put what I said in a comment in an answer, you could create a
SetMultimap
that automatically restricts the number of values it can have per key like this:快速而肮脏的单行解决方案:
mySet.remove(mySet.toArray(new Foo[mySet.size()])[0])
;)但是,我仍然会选择迭代器解决方案,因为这会更具可读性并且也应该更快。
编辑:我会选择迈克·塞缪尔的解决方案。 :)
Quick and dirty one-line solution:
mySet.remove(mySet.toArray(new Foo[mySet.size()])[0])
;)However, I'd still go for the iterator solution, since this would be more readable and should also be faster.
Edit: I'd go for Mike Samuel's solution. :)