为什么Set不提供获取与另一个元素相等的元素的操作?

Set<Foo> set = ...;
...
Foo foo = new Foo(1, 2, 3);
Foo bar = set.get(foo);   // get the Foo element from the Set that equals foo

我可以问Set是否包含一个等于bar的元素,那么为什么我不能得到那个元素呢?:(

为了澄清,equals方法被重写,但它只检查其中一个字段,而不是所有字段。两个相等的Foo对象可以有不同的值,这就是为什么我不能只用Foo。


当前回答

如果你想要HashSet中的第n个元素,你可以使用下面的解决方案, 这里我在HashSet中添加了ModelClass对象。

ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
    m1 = (ModelClass) itr.next();
    if(nth == index) {
        System.out.println(m1);
        break;
    }
}

其他回答

使用Java 8,你可以做到:

Foo foo = set.stream().filter(item->item.equals(theItemYouAreLookingFor)).findFirst().get();

但是要小心,.get()会抛出一个NoSuchElementException,或者你可以操作一个Optional项。

将set转换为list,然后使用list的get方法

Set<Foo> set = ...;
List<Foo> list = new ArrayList<Foo>(set);
Foo obj = list.get(0);
Object objectToGet = ...
Map<Object, Object> map = new HashMap<Object, Object>(set.size());
for (Object o : set) {
    map.put(o, o);
}
Object objectFromSet = map.get(objectToGet);

如果你只做一次获取,这将不是很好的执行,因为你将循环所有的元素,但当你在一个大的集合上执行多次检索时,你会注意到区别。

要准确回答“为什么Set不提供获取等于另一个元素的元素的操作?”这个问题,答案可能是:因为集合框架的设计者不是很有前瞻性。他们没有预料到您非常合理的用例,天真地试图“建模数学集合抽象”(从javadoc),只是忘记添加有用的get()方法。

现在回到隐含的问题“如何获得元素”:我认为最好的解决方案是使用Map<E,E>而不是Set<E>来将元素映射到它们自己。通过这种方式,您可以有效地从“set”中检索元素,因为Map的get()方法将使用有效的哈希表或树算法查找元素。如果愿意,可以编写自己的Set实现,提供额外的get()方法,封装Map。

以下答案在我看来是错误的:

“您不需要获取元素,因为您已经有了一个相等的对象”:断言是错误的,正如您在问题中已经表明的那样。两个相等的对象仍然可以具有与对象相等无关的不同状态。目标是访问Set中包含的元素的状态,而不是用作“查询”的对象的状态。

"You have no other option but to use the iterator": that is a linear search over a collection which is totally inefficient for large sets (ironically, internally the Set is organized as hash map or tree that could be queried efficiently). Don't do it! I have seen severe performance problems in real-life systems by using that approach. In my opinion what is terrible about the missing get() method is not so much that it is a bit cumbersome to work around it, but that most programmers will use the linear search approach without thinking of the implications.

如果你想要HashSet中的第n个元素,你可以使用下面的解决方案, 这里我在HashSet中添加了ModelClass对象。

ModelClass m1 = null;
int nth=scanner.nextInt();
for(int index=0;index<hashset1.size();index++){
    m1 = (ModelClass) itr.next();
    if(nth == index) {
        System.out.println(m1);
        break;
    }
}