我相信有一个很好的理由,但有人能解释一下为什么java.util.Set接口缺少get(int Index),或任何类似的get()方法吗?

集合似乎很适合把东西放进去,但我找不到一种优雅的方法来从中检索单个项目。

如果我知道我想要的第一项,我可以使用set.iterator().next(),但否则,似乎我必须强制转换到一个数组来检索特定索引的项?

从集合中检索数据的适当方法是什么?(与使用迭代器不同)

我相信它被排除在API之外的事实意味着有一个很好的理由不这样做——有人能启发我吗?

编辑: 这里有一些非常棒的回答,还有一些说“更多的背景”。具体的场景是一个dbUnit测试,在这个测试中,我可以合理地断言从查询返回的集合只有1个项,并且我正在尝试访问该项。

然而,这个问题在没有场景的情况下更有效,因为它仍然更集中:

set和list的区别是什么?

感谢大家的精彩回答。


因为集合没有顺序。有些实现可以(特别是那些实现java.util.SortedSet接口的实现),但这不是集合的一般属性。

如果您试图以这种方式使用集合,则应该考虑使用列表。


这是因为Set只保证惟一性,而没有说明最佳访问或使用模式。也就是说,一个Set可以是一个List或者Map,每一个都有非常不同的检索特征。


只是补充一点迈尔斯的回答中没有提到的。

如果我知道我想要第一项,我就可以 使用set.iterator().next(),但是 不然的话,我只好放弃了 数组中检索项 具体指标? 合适的方式是什么 从集合中检索数据?(其他 而不是使用迭代器)

您还应该熟悉SortedSet接口(其最常见的实现是TreeSet)。

SortedSet是一个集合(即元素是唯一的),它通过元素的自然顺序或使用一些比较器保持有序。可以使用first()和last()方法轻松访问第一个和最后一个项。SortedSet每隔一段时间就会派上用场,当您需要保持集合无重复且以某种方式有序时。

编辑:如果你需要一个Set,它的元素按照插入顺序保存(很像List),看一下LinkedHashSet。


我能想到的在集合中使用数值索引的唯一原因是为了迭代。为此,请使用

for(A a : set) { 
   visit(a); 
}

我不确定是否有人这么说过,但你需要明白以下几点:

集合中没有“first”元素。

因为,正如其他人所说,集合没有顺序。集合是一个数学概念,特别不包括排序。

Of course, your computer can't really keep a list of stuff that's not ordered in memory. It has to have some ordering. Internally it's an array or a linked list or something. But you don't really know what it is, and it doesn't really have a first element; the element that comes out "first" comes out that way by chance, and might not be first next time. Even if you took steps to "guarantee" a particular first element, it's still coming out by chance, because you just happened to get it right for one particular implementation of a Set; a different implementation might not work that way with what you did. And, in fact, you may not know the implementation you're using as well as you think you do.

People run into this ALL. THE. TIME. with RDBMS systems and don't understand. An RDBMS query returns a set of records. This is the same type of set from mathematics: an unordered collection of items, only in this case the items are records. An RDBMS query result has no guaranteed order at all unless you use the ORDER BY clause, but all the time people assume it does and then trip themselves up some day when the shape of their data or code changes slightly and triggers the query optimizer to work a different way and suddenly the results don't come out in the order they expect. These are typically the people who didn't pay attention in database class (or when reading the documentation or tutorials) when it was explained to them, up front, that query results do not have a guaranteed ordering.


这就引出了一个问题,什么时候应该使用集合,什么时候应该使用列表。通常,建议是这样的:

如果需要有序数据,请使用List 如果你需要唯一的数据,使用一个集合 如果两者都需要,可以使用SortedSet(用于按比较器排序的数据)或OrderedSet/UniqueList(用于按插入排序的数据)。不幸的是,Java API还没有OrderedSet/UniqueList。

第四种经常出现的情况是,两者都不需要。在这种情况下,你会看到一些程序员使用列表,一些使用集合。就我个人而言,我觉得把set看作一个没有顺序的列表是非常有害的——因为它真的是另一种野兽。除非你需要集唯一性或集相等性,否则总是倾向于列表。


标准Java集合中缺少一些数据结构。

包(类似set,但可以多次包含元素)

UniqueList(有序列表,每个元素只能包含一次)

在这种情况下,你似乎需要一个唯一性列表

如果您需要灵活的数据结构,您可能会对谷歌Collections感兴趣


根据Set集合的定义,Set中的元素是无序的。所以它们不能被索引访问。

但是为什么我们没有一个get(object)方法,不是通过提供索引作为参数,而是提供一个与我们正在寻找的对象相等的对象? 通过这种方式,我们可以访问Set中元素的数据,只需要知道equal方法使用的属性。


实际上,在编写使用对象-关系映射的JavaEE应用程序(例如Hibernate)时,这是一个反复出现的问题;在所有回复这里的人中,Andreas Petersson是唯一一个理解真正问题并给出正确答案的人:Java缺少一个UniqueList!(或者您也可以将其称为OrderedSet或IndexedSet)。

Maxwing提到了这个用例(在这个用例中,您需要有序且唯一的数据),他建议使用SortedSet,但这不是Marty Pitt真正需要的。

这个“IndexedSet”和SortedSet不一样——在SortedSet中,元素是通过比较器排序的(或者使用它们的“自然”排序)。

但相反,它更接近于LinkedHashSet(其他人也建议),甚至更接近于一个(也不存在)"ArrayListSet",因为它保证元素以插入时相同的顺序返回。

但是LinkedHashSet是一个实现,而不是一个接口!所需要的是IndexedSet(或ListSet,或OrderedSet,或UniqueList)接口!这将允许程序员指定他需要一个具有特定顺序且没有重复的元素集合,然后用任何实现实例化它(例如Hibernate提供的实现)。

因为JDK是开源的,也许这个接口最终会被包含在Java 7中…


要获取Set中的元素,我使用以下命令:

public T getElement(Set<T> set, T element) {
T result = null;
if (set instanceof TreeSet<?>) {
    T floor = ((TreeSet<T>) set).floor(element);
    if (floor != null && floor.equals(element))
    result = floor;
} else {
    boolean found = false;
    for (Iterator<T> it = set.iterator(); !found && it.hasNext();) {
    if (true) {
        T current = it.next();
        if (current.equals(element)) {
        result = current;
        found = true;
        }
    }
    }
}
return result;
}

我遇到了这样的情况,我实际上想要一个通过索引访问的SortedSet(我同意其他海报,访问一个没有索引的无序集是没有意义的)。 例如,在树中,我希望对子节点进行排序,不允许重复子节点。

我需要通过索引访问来显示它们,set属性可以有效地消除重复。

在java中找不到合适的集合。util或谷歌集合,我发现它直接实现它自己。基本思想是包装SortedSet并在需要通过索引访问时创建一个List(并且在SortedSet被更改时忘记该列表)。当然,这只有在更改包装的SortedSet和在集合的生命周期中分离访问列表时才有效。否则它就像一个经常排序的列表,也就是说太慢了。

对于大量的子节点,这大大提高了我通过Collections.sort进行排序的列表的性能。


如果你要在一个集合中通过索引进行大量的随机访问,你可以得到它的元素的数组视图:

Object[] arrayView = mySet.toArray();
//do whatever you need with arrayView[i]

但它有两个主要缺点:

它的内存效率不高,因为需要为整个集合创建一个数组。 如果集合被修改,视图就会过时。


你可以用new ArrayList<T>(set)。get(index)


The reason why the Set interface doesn't have a get index-type call or even something even more basic, such as first() or last(), is because it is an ambiguous operation, and therefore a potentially dangerous operation. If a method returns a Set, and you call, say first() method on it, what is the expected result, given that the a generic Set makes no guarantees on the ordering? The resultant object could very well vary between each call of the method, or it might not and lull you into a false sense of security, until the library you're using changes changes the implementation underneath and now you find that all your code breaks for no particular reason.

这里列出的关于变通办法的建议很好。如果需要索引访问,请使用列表。对泛型Set使用迭代器或toArray时要小心,因为a)不能保证顺序,b)不能保证顺序不会随着后续调用或不同的底层实现而改变。如果你需要介于两者之间的东西,SortedSet或LinkedHashSet就是你想要的。

// 我希望Set界面有一个get-random-元素。


如果您不介意要排序的集合,那么您可能有兴趣看看索引树映射项目。

增强的TreeSet/TreeMap提供了通过索引访问元素或获取元素索引的功能。实现基于更新RB树中的节点权重。所以这里没有迭代,也没有列表备份。


请注意,只有2个基本的数据结构可以通过索引访问。

数组数据结构可以通过O(1)时间复杂度的索引访问,实现get(int index)操作。 LinkedList数据结构也可以通过索引访问,但要用O(n)时间复杂度来实现get(int index)操作。

在Java中,ArrayList是使用Array数据结构实现的。

而Set数据结构通常可以通过HashTable/HashMap或BalancedTree数据结构实现,为了快速检测元素是否存在并添加不存在的元素,通常一个实现良好的Set可以实现O(1)个时间复杂度包含操作。在Java中,HashSet是Set最常用的实现,它是通过调用HashMap API来实现的,HashMap是使用链表(Array和LinkedList的组合)来实现的。

由于Set可以通过不同的数据结构实现,因此没有get(int index)方法。


set是一个无序项的集合。如果Set有一个get(int index)就没有意义了,因为 Set没有索引,你只能猜测它的值。

如果你真的想要这个,编写一个方法从Set中获取随机元素。


Set是一个接口,它的一些实现类是HashSet、TreeSet和LinkedHashSet。它在底层使用HashMap来存储值。因为HashMap不保留顺序,所以不可能通过索引获取值。

你现在肯定在想Set是如何使用HashMap的,因为HashMap存储了一个键和值对,而Set没有。有效的问题。当你在Set中添加一个元素时,它在内部维护一个HashMap,其中键是你想在Set中输入的元素,值是虚拟常量。下面是add函数的内部实现。因此,HashMap中的所有键都将具有相同的常量值。

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

因为Set在随机位置存储唯一的元素,并且在内部它使用多个数据结构。即数组,链表,带有哈希的树。

链接 https://en.wikipedia.org/wiki/Set_ (abstract_data_type)