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

时间:2009-04-20 19:19:40

标签: java data-structures collections set

我确信这是有充分理由的,但有人可以解释为什么java.util.Set界面缺少get(int Index)或任何类似的get()方法吗?

似乎套装很适合放入,但我找不到从中检索单个项目的优雅方法。

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

从集合中检索数据的适当方法是什么? (除了使用迭代器之外)

我确信它被排除在API之外意味着有一个很好的理由不这样做 - 有人可以开导我吗?

修改 这里有一些非常好的答案,还有一些说“更多背景”。特定场景是一个dbUnit测试,我可以合理地断言查询返回的集只有一个项目,我试图访问该项目。

但是,如果没有这种情况,这个问题会更有效,因为它仍然更受关注:

set和list 之间有什么区别。

感谢所有人给出了下面的精彩答案。

20 个答案:

答案 0 :(得分:171)

因为套装没有订购。有些实现(特别是那些实现java.util.SortedSet接口的实现),但这不是集合的一般属性。

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

答案 1 :(得分:73)

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

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

此“IndexedSet”与SortedSet不同 - 在SortedSet中,元素使用比较器(或使用“自然”排序)进行排序。

但是它更接近LinkedHashSet(其他人也建议),或者更接近于(也不存在)“ArrayListSet”,因为它保证元素以与插入时相同的顺序返回。 / p>

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

由于JDK是开源的,也许这个接口最终将包含在Java 7中......

答案 2 :(得分:28)

只需添加mmyers' answer中未提及的一个点。

  

如果我知道我想要第一个项目,我可以   使用set.iterator()。next(),但是   否则我似乎要投   用于检索项目的数组   具体指数?

     

适当的方法是什么?   从一组中检索数据? (其他   而不是使用迭代器)

您还应该熟悉SortedSet界面(最常见的实现是TreeSet)。

SortedSet是一个Set(即元素是唯一的),它由元素的自然排序或使用某些Comparator保持排序。您可以使用first()last()方法轻松访问第一个和最后一个项目。 SortedSet每隔一段时间派上用场,当你需要保持你的收藏品无重复和以某种方式订购时。

修改:如果您需要一个其元素按插入顺序保存的Set(非常类似于List),请查看LinkedHashSet

答案 3 :(得分:24)

当您应该使用集合以及何时应该使用列表时,会出现这种问题。通常,建议如下:

  1. 如果您需要订购数据,请使用列表
  2. 如果您需要唯一数据,请使用Set
  3. 如果您需要两者,请使用:SortedSet(对于比较器排序的数据)或OrderedSet / UniqueList(对于按插入排序的数据)。不幸的是,Java API还没有OrderedSet / UniqueList。
  4. 经常出现的第四种情况是你不需要。在这种情况下,您会看到一些程序员使用列表,一些使用集合。就个人而言,我觉得将它设置为无需排序的列表是非常有害的 - 因为它实际上是另一个野兽。除非你需要设置唯一性或设置相等的东西,否则总是喜欢列表。

答案 4 :(得分:17)

我不确定是否有人以这种方式拼写出来,但您需要了解以下内容:

集合中没有“第一个”元素。

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

当然,您的计算机无法真正保留内存中未订购的内容列表。它必须有一些订购。在内部,它是一个数组或链表或其他东西。但你真的不知道它是什么,它并没有真正的第一个元素; “第一个”出来的元素是偶然出现的,下次可能不是第一个。即使你采取措施“保证”某个特定的第一个元素,它仍然是偶然出现的,因为你恰好正确地实现了一个Set的一个特定实现;不同的实现可能与您所做的不同。而且,实际上,您可能不会像您认为的那样知道您正在使用的实现。

人们遇到这个ALL。 THE。时间。与RDBMS系统并不明白。 RDBMS查询返回一组记录。这是与数学相同类型的集合:无序的项目集合,仅在这种情况下,项目是记录。除非你使用ORDER BY子句,否则RDBMS查询结果根本没有保证的顺序,但是人们一直认为这样做然后在某天当数据或代码的形状稍微改变并触发查询优化器工作时自行启动一种不同的方式突然之间,结果并没有按照他们期望的顺序出现。这些通常是那些在数据库类中(或在阅读文档或教程时)没有注意的人,当事先向他们解释时,查询结果没有保证的顺序。

答案 5 :(得分:10)

标准java集合中缺少某些数据结构。

Bag(喜欢set但可以多次包含元素)

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

在这种情况下,你似乎需要一个单作家

如果您需要灵活的数据结构,可能会对Google Collections

感兴趣

答案 6 :(得分:7)

这是真的,根据Set Collection的定义,Set中的元素没有排序。所以他们无法通过索引访问。

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

答案 7 :(得分:7)

如果要按集合中的索引进行大量随机访问,则可以获取其元素的数组视图:

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

但有两个主要缺点:

  1. 这不是内存效率,因为需要创建整个集合的数组。
  2. 如果修改了该集,则视图将过时。

答案 8 :(得分:5)

这是因为Set仅保证唯一性,但对最佳访问或使用模式一无所知。即,Set可以是List或Map,每个都具有非常不同的检索特征。

答案 9 :(得分:5)

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

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

答案 10 :(得分:3)

我遇到了一些情况,我实际上想要一个排序设置,通过索引访问(我同意其他海报访问带有索引的未排序集合没有意义)。 一个例子是一棵树,我想要对孩子进行分类,不允许重复的孩子。

我需要通过索引进行访问以显示它们,并且设置属性可以有效地消除重复项。

在java.util或google集合中找不到合适的集合,我发现自己直接实现它很简单。基本思想是在需要通过索引进行访问时包装SortedSet并创建List(并在更改SortedSet时忘记列表)。当然,这仅在更改包装的SortedSet时有效地工作,并且在Collection的生命周期中访问列表是分开的。否则它的行为类似于经常排序的列表,即太慢。

有了大量的孩子,这比我通过Collections.sort排序的列表提高了很多。

答案 11 :(得分:2)

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

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

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

虽然设置数据结构通常可以通过 HashTable / HashMap BalancedTree 数据结构来实现,以便快速检测元素是否存在并添加不存在的元素,通常是实施良好的,可以实现O(1)时间复杂度contains操作。在Java中,HashSet Set 最常用的实现,它通过调用HashMap API实现,HashMap使用单独链接实现链接列表数组 LinkedList 的组合)。

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

答案 12 :(得分:1)

Set 接口之所以没有get索引类型调用,甚至更基本的东西,例如first()或last(),是因为它是一个模糊的操作,因此是一个潜在的危险操作。如果一个方法返回一个Set,并且你调用它,比如说first()方法,那么预期的结果是什么,假设一个泛型Set不能保证排序?结果对象可以在方法的每次调用之间很好地变化,或者它可能不会让你陷入虚假的安全感,直到你使用的库更改改变了下面的实现,现在你发现你的所有代码都中断了没有特别的原因。

此处列出的有关变通方法的建议很好。如果需要索引访问,请使用列表。小心使用迭代器或使用泛型Set的toArray,因为a)不能保证排序和b)不能保证排序不会随后续调用或不同的底层实现而改变。如果你需要介于两者之间,可以使用SortedSet或LinkedHashSet。

// 我希望Set接口有一个get-random-element。

答案 13 :(得分:1)

java.util.Set是未订购商品的集合。如果Set有一个get(int index),那没有任何意义,因为 Set没有索引,您也只能猜测该值。

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

答案 14 :(得分:0)

您可以执行new ArrayList<T>(set).get(index)

答案 15 :(得分:0)

如果您不介意要对其进行排序,那么您可能有兴趣查看indexed-tree-map项目。

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

答案 16 :(得分:0)

尝试将此代码作为访问索引的替代选项

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]);
    }
}

这将打印100。

答案 17 :(得分:0)

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;
}

答案 18 :(得分:0)

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

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

答案 19 :(得分:-3)

要获取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;
}