为什么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。


当前回答

如果你看一下java.util.HashSet实现的前几行,你会看到:

public class HashSet<E>
    ....
    private transient HashMap<E,Object> map;

HashSet在内部使用HashMap,这意味着如果你直接使用HashMap并使用与键相同的值,你会得到你想要的效果,并节省一些内存。

其他回答

Why:

Set似乎在提供比较手段方面发挥了有用的作用。它被设计为不存储重复的元素。

由于这种意图/设计,如果要获得()对存储对象的引用,然后更改它,则Set的设计意图可能会受到阻碍,并可能导致意想不到的行为。

来自JavaDocs

如果使用可变对象作为set元素,必须非常小心。当对象是集合中的元素时,如果对象的值以影响相等比较的方式更改,则不指定集合的行为。

How:

现在已经引入了流,我们可以做以下事情

mySet.stream()
.filter(object -> object.property.equals(myProperty))
.findFirst().get();

看起来合适的使用对象是番石榴中的Interner:

为其他不可变提供与String.intern()相同的行为 类型。常见的实现可以从Interners获得 类。

它也有一些非常有趣的杠杆,比如concurrencyLevel,或者使用的引用类型(可能值得注意的是,它没有提供softinternet,我认为这比weakinternet更有用)。

如果你想要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;
    }
}

要准确回答“为什么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.

遵循可以是一种方法

   SharedPreferences se_get = getSharedPreferences("points",MODE_PRIVATE);
   Set<String> main = se_get.getStringSet("mydata",null);
   for(int jk = 0 ; jk < main.size();jk++)
   {
      Log.i("data",String.valueOf(main.toArray()[jk]));
   }