简体   繁体   English

为什么 java.util.Set 没有 get(int index)?

[英]Why doesn't java.util.Set have get(int index)?

I'm sure there's a good reason, but could someone please explain why the java.util.Set interface lacks get(int Index) , or any similar get() method?我确定有一个很好的理由,但是有人可以解释为什么java.util.Set接口缺少get(int Index)或任何类似的get()方法吗?

It seems that sets are great for putting things into, but I can't find an elegant way of retrieving a single item from it.似乎集合非常适合放入东西,但我找不到一种优雅的方式从中检索单个项目。

If I know I want the first item, I can use set.iterator().next() , but otherwise it seems I have to cast to an Array to retrieve an item at a specific index?如果我知道我想要第一个项目,我可以使用set.iterator().next() ,但否则似乎我必须转换为 Array 以检索特定索引处的项目?

What are the appropriate ways of retrieving data from a set?从集合中检索数据的适当方法是什么? (other than using an iterator) (除了使用迭代器)

I'm sure the fact that it's excluded from the API means there's a good reason for not doing this -- could someone please enlighten me?我确信它被排除在 API 之外的事实意味着有一个很好的理由不这样做——有人可以启发我吗?

EDIT: Some extremely great answers here, and a few saying "more context".编辑:这里有一些非常好的答案,还有一些说“更多上下文”。 The specific scenario was a dbUnit test, where I could reasonably assert that the returned set from a query had only 1 item, and I was trying to access that item.特定场景是 dbUnit 测试,我可以合理地断言从查询返回的集合只有 1 个项目,并且我试图访问该项目。

However, the question is more valid without the scenario, as it remains more focussed:然而,这个问题在没有场景的情况下更有效,因为它仍然更加集中:

What's the difference between set and list . set 和 list 有什么区别

Thanks to all for the fantastic answers below.感谢下面所有精彩的回答。

Because sets have no ordering.因为集合没有顺序。 Some implementations do (particularly those implementing the java.util.SortedSet interface), but that is not a general property of sets.一些实现可以(特别是那些实现java.util.SortedSet接口的实现),但这不是集合的一般属性。

If you're trying to use sets this way, you should consider using a list instead.如果您尝试以这种方式使用集合,则应考虑改用列表。

Actually this is a recurring question when writing JavaEE applications which use Object-Relational Mapping (for example with Hibernate);实际上,在编写使用对象关系映射(例如使用 Hibernate)的 JavaEE 应用程序时,这是一个反复出现的问题; and from all the people who replied here, Andreas Petersson is the only one who understood the real issue and offered the correct answer to it: Java is missing a UniqueList!在所有在这里回复的人中,Andreas Petersson 是唯一了解真正问题并提供正确答案的人:Java 缺少一个 UniqueList! (or you can also call it OrderedSet, or IndexedSet). (或者您也可以将其称为 OrderedSet 或 IndexedSet)。

Maxwing mentioned this use-case (in which you need ordered AND unique data) and he suggested the SortedSet, but this is not what Marty Pitt really needed. Maxwing 提到了这个用例(其中您需要有序且唯一的数据)并且他建议使用 SortedSet,但这并不是 Marty Pitt 真正需要的。

This "IndexedSet" is NOT the same as a SortedSet - in a SortedSet the elements are sorted by using a Comparator (or using their "natural" ordering).此“IndexedSet”与 SortedSet 不同 - 在 SortedSet 中,元素通过使用比较器(或使用它们的“自然”排序)进行排序。

But instead it is closer to a LinkedHashSet (which others also suggested), or even more so to an (also inexistent) "ArrayListSet", because it guarantees that the elements are returned in the same order as they were inserted.但相反,它更接近于 LinkedHashSet(其他人也建议),或者更接近于(同样不存在的)“ArrayListSet”,因为它保证元素的返回顺序与它们插入的顺序相同。

But the LinkedHashSet is an implementation, not an interface!但是 LinkedHashSet 是一个实现,而不是一个接口! What is needed is an IndexedSet (or ListSet, or OrderedSet, or UniqueList) interface!需要的是一个IndexedSet(或ListSet,或OrderedSet,或UniqueList)接口! This will allow the programmer to specify that he needs a collection of elements that have a specific order and without duplicates, and then instantiate it with any implementation (for example an implementation provided by Hibernate).这将允许程序员指定他需要具有特定顺序且没有重复的元素集合,然后使用任何实现(例如 Hibernate 提供的实现)实例化它。

Since JDK is open-source, maybe this interface will be finally included in Java 7...由于JDK是开源的,也许这个接口最终会被包含在Java 7中......

Just adding one point that was not mentioned in mmyers' answer .只是添加一点在mmyers 的回答中没有提到。

If I know I want the first item, I can use set.iterator().next(), but otherwise it seems I have to cast to an Array to retrieve an item at a specific index?如果我知道我想要第一个项目,我可以使用 set.iterator().next(),但否则我似乎必须转换为一个数组来检索特定索引处的项目?

What are the appropriate ways of retrieving data from a set?从集合中检索数据的适当方法是什么? (other than using an iterator) (除了使用迭代器)

You should also familiarise yourself with the SortedSet interface (whose most common implementation is TreeSet ).您还应该熟悉SortedSet接口(其最常见的实现是TreeSet )。

A SortedSet is a Set (ie elements are unique) that is kept ordered by the natural ordering of the elements or using some Comparator . SortedSet 是一个 Set(即元素是唯一的),它通过元素的自然顺序或使用一些Comparator保持有序。 You can easily access the first and last items using first() and last() methods.您可以使用first()last()方法轻松访问第一个和最后一个项目。 A SortedSet comes in handy every once in a while, when you need to keep your collection both duplicate-free and ordered in a certain way. SortedSet每隔一段时间就会派上用场,当您需要保持您的集合无重复并以某种方式排序时。

Edit : If you need a Set whose elements are kept in insertion-order (much like a List), take a look at LinkedHashSet .编辑:如果您需要一个元素按插入顺序保存的 Set(很像 List),请查看LinkedHashSet

This kind of leads to the question when you should use a set and when you should use a list.这导致了何时应该使用集合以及何时应该使用列表的问题。 Usually, the advice goes:通常,建议如下:

  1. If you need ordered data, use a List如果您需要有序数据,请使用列表
  2. If you need unique data, use a Set如果您需要唯一数据,请使用 Set
  3. If you need both, use either: a SortedSet (for data ordered by comparator) or an OrderedSet/UniqueList (for data ordered by insertion).如果两者都需要,请使用:SortedSet(用于按比较器排序的数据)或 OrderedSet/UniqueList(用于按插入排序的数据)。 Unfortunately the Java API does not yet have OrderedSet/UniqueList.不幸的是,Java API 还没有 OrderedSet/UniqueList。

A fourth case that appears often is that you need neither.经常出现的第四种情况是您两者都不需要。 In this case you see some programmers go with lists and some with sets.在这种情况下,您会看到一些程序员使用列表,而一些程序员使用集合。 Personally I find it very harmful to see set as a list without ordering - because it is really a whole other beast.就我个人而言,我认为将 set 视为一个没有排序的列表是非常有害的——因为它真的是一个完全不同的野兽。 Unless you need stuff like set uniqueness or set equality, always favor lists.除非您需要设置唯一性或设置相等性之类的东西,否则请始终使用列表。

I'm not sure if anybody has spelled it out exactly this way, but you need to understand the following:我不确定是否有人完全这样拼写过,但您需要了解以下内容:

There is no "first" element in a set.集合中没有“第一个”元素。

Because, as others have said, sets have no ordering.因为,正如其他人所说,集合没有顺序。 A set is a mathematical concept that specifically does not include ordering.集合是一个数学概念,特别不包括排序。

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;即使您采取措施来“保证”某个特定的第一个元素,它仍然是偶然出现的,因为您恰好在 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.用 RDBMS 系统,不明白。 An RDBMS query returns a set of records. RDBMS 查询返回一组记录。 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.除非您使用 ORDER BY 子句,否则 RDBMS 查询结果根本没有保证的顺序,但人们总是假设它确实如此,然后有一天当他们的数据或代码的形状略有变化并触发查询优化器工作时,他们自己就会绊倒一种不同的方式,突然结果并没有按照他们期望的顺序出现。 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.这些通常是那些在数据库课程中(或在阅读文档或教程时)没有注意的人,当事先向他们解释查询结果没有保证的顺序时。

some data structures are missing from the standard java collections.标准 java 集合中缺少一些数据结构。

Bag (like set but can contain elements multiple times) Bag(类似于 set 但可以多次包含元素)

UniqueList (ordered list, can contain each element only once) UniqueList(有序列表,每个元素只能包含一次)

seems you would need a uniquelist in this case在这种情况下,您似乎需要一个 uniquelist

if you need flexible data structures, you might be interested in Google Collections如果您需要灵活的数据结构,您可能会对Google Collections感兴趣

That's true, element in Set are not ordered, by definition of the Set Collection.确实如此,根据 Set 集合的定义,Set 中的元素没有排序。 So they can't be access by an index.所以它们不能被索引访问。

But why don't we have a get(object) method, not by providing the index as parameter, but an object that is equal to the one we are looking for?但是为什么我们没有 get(object) 方法,不是通过提供索引作为参数,而是提供一个与我们正在寻找的对象相等的对象? By this way, we can access the data of the element inside the Set, just by knowing its attributes used by the equal method.通过这种方式,我们可以访问Set内部元素的数据,只需知道equal方法使用的属性。

If you are going to do lots of random accesses by index in a set, you can get an array view of its elements:如果您要通过集合中的索引进行大量随机访问,您可以获得其元素的数组视图:

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

There are two main drawbacks though:但是有两个主要缺点:

  1. It's not memory efficient, as an array for the whole set needs to be created.它的内存效率不高,因为需要为整个集合创建一个数组。
  2. If the set is modified, the view becomes obsolete.如果该集合被修改,则视图将过时。

That is because Set only guarantees uniqueness, but says nothing about the optimal access or usage patterns.那是因为 Set 只保证唯一性,而没有说明最佳访问或使用模式。 Ie, a Set can be a List or a Map, each of which have very different retrieval characteristics.即,一个集合可以是一个列表或一个映射,每个都有非常不同的检索特征。

The only reason I can think of for using a numerical index in a set would be for iteration.我能想到的在集合中使用数字索引的唯一原因是迭代。 For that, use为此,使用

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

I ran into situations where I actually wanted a Sorted Set with access via index (I concur with other posters that accessing an unsorted Set with an index makes no sense).我遇到了,我其实是想一个有序集合通过索引(我与其他海报同意,访问一个未排序的设置与索引是没有意义的)访问的情况。 An example would be a tree where I wanted the children to be sorted and duplicate children were not allowed.一个例子是一棵树,我希望对孩子进行排序并且不允许重复的孩子。

I needed the access via index to display them and the set attributes came in handy to efficiently eliminate duplicates.我需要通过索引访问来显示它们,并且设置的属性派上用场,可以有效地消除重复项。

Finding no suitable collection in java.util or google collections, I found it straightforward to implement it myself.在 java.util 或 google 集合中找不到合适的集合,我发现自己实现它很简单。 The basic idea is to wrap a SortedSet and create a List when access via index is required (and forget the list when the SortedSet is changed).基本思想是包装一个 SortedSet 并在需要通过索引访问时创建一个 List (并且在 SortedSet 更改时忘记该列表)。 This does of course only work efficiently when changing the wrapped SortedSet and accessing the list is separated in the lifetime of the Collection.这当然只有在更改包装的 SortedSet 并且访问列表在集合的生命周期中分开时才有效。 Otherwise it behaves like a list which is sorted often, ie too slow.否则它就像一个经常排序的列表,即太慢。

With large numbers of children, this improved performance a lot over a list I kept sorted via Collections.sort.对于大量孩子,这比我通过 Collections.sort 排序的列表大大提高了性能。

Please note only 2 basic data structure can be accessed via index.请注意,只有 2 个基本数据结构可以通过索引访问。

  • Array data structure can be accessed via index with O(1) time complexity to achieve get(int index) operation.可以通过索引访问数组数据结构,时间复杂度为O(1)以实现get(int index)操作。
  • LinkedList data structure can also be accessed via index, but with O(n) time complexity to achieve get(int index) operation. LinkedList数据结构也可以通过索引访问,但是实现get(int index)操作的时间复杂度为O(n)

In Java, ArrayList is implemented using Array data structure.在 Java 中, ArrayList是使用Array数据结构实现的。

While Set data structure usually can be implemented via HashTable/HashMap or BalancedTree data structure, for fast detecting whether an element exists and add non-existing element, usually a well implemented Set can achieve O(1) time complexity contains operation.Set数据结构通常可以通过HashTable/HashMapBalancedTree数据结构来实现,为了快速检测元素是否存在并添加不存在的元素,通常一个实现良好的Set可以实现O(1)时间复杂度的contains操作。 In Java, HashSet is the most common used implementation of Set , it is implemented by calling HashMap API, and HashMap is implemented using separate chaining with linked lists (a combination of Array and LinkedList ).在 Java 中, HashSetSet最常用的实现,它是通过调用HashMap API 来实现的,而HashMap是使用链表ArrayLinkedList的组合)单独链接来实现的。

Since Set can be implemented via different data structure, there is no get(int index) method for it.由于Set可以通过不同的数据结构实现,因此没有get(int 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. Set接口之所以没有 get 索引类型的调用,甚至没有更基本的调用,例如 first() 或 last(),是因为它是一个不明确的操作,因此是一个潜在的危险操作。 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?如果一个方法返回一个 Set,并且你在它上面调用了 first() 方法,那么预期的结果是什么,因为一个通用的 Set 对排序没有保证? 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.结果对象在每次调用方法之间可能会有所不同,或者它可能不会并让您陷入错误的安全感,直到您使用的库更改了下面的实现,现在您发现所有代码都中断了没有特别的理由。

The suggestions about workarounds listed here are good.此处列出的有关变通方法的建议很好。 If you need indexed access, use a list.如果您需要索引访问,请使用列表。 Be careful with using iterators or toArray with a generic Set, because a) there is no guarantee on the ordering and b) there is no guarantee that the ordering will not change with subsequent invocations or with different underlying implementations.使用迭代器或 toArray 与泛型 Set 时要小心,因为 a) 不能保证排序,b) 不能保证排序不会随着后续调用或不同的底层实现而改变。 If you need something in between, a SortedSet or a LinkedHashSet is what you want.如果您需要介于两者之间的东西,SortedSet 或 LinkedHashSet 就是您想要的。

// I do wish the Set interface had a get-random-element though. // 我确实希望 Set 接口有一个 get-random-element。

java.util.Set is a collection of un-ordered items. java.util.Set是无序项的集合。 It doesn't make any sense if the Set has a get(int index), because Set doesn't has an index and also you only can guess the value.如果 Set 有 get(int index) 没有任何意义,因为 Set 没有索引,而且您只能猜测值。

If you really want this, code a method to get random element from Set.如果你真的想要这个,编写一个方法来从 Set 中获取随机元素。

If you don't mind the set to be sorted then you may be interested to take a look at the indexed-tree-map project.如果您不介意要排序的集合,那么您可能有兴趣查看indexed-tree-map项目。

The enhanced TreeSet/ TreeMap provides access to elements by index or getting the index of an element.增强的 TreeSet/ TreeMap通过索引或获取元素的索引来提供对元素的访问。 And the implementation is based on updating node weights in the RB tree.实现是基于更新 RB 树中的节点权重。 So no iteration or backing up by a list here.所以这里没有迭代或备份列表。

Try this Code as an alternate option to access through indices 尝试使用此代码作为通过索引访问的备用选项

import java.io.*;
import java.util.*;
class GFG {
public static void main (String[] args) {
    HashSet <Integer> mySet=new HashSet<Integer>();
    mySet.add(100);
    mySet.add(100);
    int n = mySet.size();
    Integer arr[] = new Integer[n];
    arr = mySet.toArray(arr);
    System.out.println(arr[0]);
    }
}

This will print 100. 这将打印100。

Set is an interface and some of its implementation classes are HashSet, TreeSet and LinkedHashSet. Set 是一个接口,它的一些实现类是 HashSet、TreeSet 和 LinkedHashSet。 It uses HashMap under the hood to store values.它在底层使用 HashMap 来存储值。 Because HashMap does not preserve the order, it is not possible to get value by index.由于 HashMap 不保留顺序,因此无法通过索引获取值。

You now must be thinking how Set is using HashMap since HashMap stores a key, value pair but the Set does not.您现在一定在想 Set 是如何使用 HashMap 的,因为 HashMap 存储了一个键值对,而 Set 没有。 valid question.有效的问题。 when you add an element in Set, internally, it maintains a HashMap where the key is the element you want to enter in Set and the value is the dummy constant.当您在 Set 中添加元素时,它在内部维护一个 HashMap,其中键是您要在 Set 中输入的元素,值是虚拟常量。 Below is an internal implementation of add function.下面是 add 函数的内部实现。 Hence, all the keys in the HashMap will have the same constant value.因此,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;
}

Because the Set stores unique elements in random locations and Internally It uses multiple data structures.因为 Set 在随机位置存储唯一元素,并且在内部使用多种数据结构。 ie Array, linked list, a tree with hashing.即数组、链表、带有散列的树。

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

你可以做new ArrayList<T>(set).get(index)

To get element in a Set, i use to following one:要获取 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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM