为什么没有java.util.Set get(int index)?
我确定有一个很好的理由,但是有人能解释为什么java.util.Set
接口缺lessget(int Index)
或者任何类似的get()
方法吗?
看起来套是伟大的东西进入,但我找不到一个优雅的方式从它检索单个项目。
如果我知道我想要的第一个项目,我可以使用set.iterator().next()
,但否则似乎我必须转换到一个数组来检索特定索引的项目?
从一个集合中检索数据有什么合适的方法? (除了使用迭代器)
我相信,从API中排除这个事实意味着不这样做的一个很好的理由 – 请问有人能够启发我吗?
编辑:这里有一些非常好的答案,还有一些说“更多的上下文”。 具体的情况是一个dbUnittesting,我可以合理地断言,查询返回的集合只有一个项目,我试图访问该项目。
但是,如果没有这种情况,这个问题就更加有效了,因为它仍然更加集中:
设置和列表有什么区别 。
感谢所有的下面的美妙的答案。
因为集合没有sorting。 有些实现(特别是那些实现java.util.SortedSet
接口的实现),但这不是集合的一般属性。
如果您尝试以这种方式使用集合,则应考虑使用列表。
实际上,在编写使用对象关系映射(例如Hibernate)的JavaEE应用程序时,这是一个反复出现的问题。 而且在这里回答的所有人中,Andreas Petersson是唯一一位了解真正问题并提供正确答案的人:Java缺lessUniqueList! (或者你也可以把它叫做OrderedSet或者IndexedSet)。
Maxwing提到了这个用例(在这个用例中需要有序和唯一的数据),他提出了SortedSet,但这不是Marty Pitt真正需要的。
这个“IndexedSet”与SortedSet不同 – 在SortedSet中,元素使用比较器(或使用它们的“自然”sorting)进行sorting。
但是更接近LinkedHashSet(其他人也build议),甚至更接近于(也不存在的)“ArrayListSet”,因为它保证元素以与插入顺序相同的顺序返回。
但LinkedHashSet是一个实现,而不是一个接口! 需要的是一个IndexedSet(或ListSet,OrderedSet或UniqueList)接口! 这将允许程序员指定他需要一个具有特定顺序且没有重复的元素的集合,然后用任何实现(例如由Hibernate提供的实现)实例化它。
由于JDK是开源的,也许这个接口将被包含在Java 7中…
只是增加一个没有在mmyers的答案中提到的观点。
如果我知道我想要的第一个项目,我可以使用set.iterator()。next(),但否则似乎我必须转换到一个数组检索特定索引的项目?
从一个集合中检索数据有什么合适的方法? (除了使用迭代器)
您还应该熟悉SortedSet
接口(其最常见的实现是TreeSet
)。
SortedSet是一个集合(即元素是唯一的),通过元素的自然sorting或使用某个Comparator
来保持sorting。 您可以使用first()
和last()
方法轻松访问第一个和最后一个项目。 SortedSet
每隔一段时间就派上用场,当你需要保持你的collections都是免费的,并以某种方式订购。
编辑 :如果你需要一个其元素保持插入顺序的集合(很像列表),看看LinkedHashSet
。
这种types的问题会导致您何时应该使用一个集合,何时应该使用一个列表。 通常,build议是:
- 如果您需要订购数据,请使用列表
- 如果您需要唯一的数据,请使用Set
- 如果同时需要,可以使用:SortedSet(用于按比较器sorting的数据)或OrderedSet / UniqueList(用于按插入sorting的数据)。 不幸的是,Java API还没有OrderedSet / UniqueList。
经常出现的第四种情况是你既不需要。 在这种情况下,你可以看到一些程序员用列表和一些列表。 就我个人而言,我觉得把它看成一个没有命令的列表是非常有害的 – 因为它实际上是一个完整的其他的野兽。 除非你需要像设置唯一性或设置平等的东西,总是喜欢名单。
我不确定是否有人用这种方式拼出来,但是你需要了解以下内容:
一个集合中没有“第一个”元素。
正如其他人所说,因为集合没有sorting。 一组是一个math概念,具体不包括sorting。
当然,你的电脑不能真正保留一些没有在内存中sorting的东西。 它必须有一些命令。 内部是一个数组或链表或其他东西。 但是你不知道它是什么,它并没有真正的第一个元素。 第一个出来的元素偶然出现,下次可能不是第一个。 即使你采取措施来“保证”某个特定的元素,它仍然是偶然出现的,因为你恰好为某个特定的Set实现做准备; 一个不同的实现可能不会像你所做的那样工作。 事实上,你可能不知道你正在使用的实现以及你认为你正在使用的实现。
人们遇到这一切。 THE。 时间。 与RDBMS系统,并不明白。 一个RDBMS查询返回一组logging。 这是从math中相同types的集合:一个无序的项目集合,只有在这种情况下,项目是logging。 一个RDBMS查询结果根本没有保证的顺序,除非你使用ORDER BY子句,但是人们总是假设它是这样做的,然后有一天他们的数据或代码的形状会稍微改变,并触发查询优化器工作一个不同的方式,突然间结果不按照他们期望的顺序出来。 这些通常是那些在数据库类中没有引起注意的人(或者在阅读文档或者教程的时候),在向他们解释的时候,查询结果没有保证的顺序。
一些数据结构从标准java集合中丢失。
袋子(像套,但可以包含元素多次)
UniqueList(有序列表,只能包含每个元素一次)
在这种情况下,你似乎需要一个独特的主义者
如果您需要灵活的数据结构,您可能对Googlecollections集感兴趣
这是真的,根据Set集合的定义,Set中的元素不是有序的。 所以他们不能被索引访问。
但是为什么我们没有get(object)方法,而不是通过提供索引作为参数,而是一个与我们正在寻找的对象相等的对象? 通过这种方式,我们可以通过知道等式所使用的属性来访问Set内部元素的数据。
如果你要通过一个集合中的索引做大量的随机访问,你可以得到它的元素的数组视图:
Object[] arrayView = mySet.toArray(); //do whatever you need with arrayView[i]
虽然有两个主要的缺点:
- 这不是内存高效的,因为需要创build整个数组的数组。
- 如果该设置被修改,则该视图变为废弃。
这是因为Set只能保证唯一性,而没有提到最佳访问或使用模式。 也就是说,一个集合可以是一个列表或一个地图,每一个都有非常不同的检索特征。
我能想到在集合中使用数字索引的唯一原因是迭代。 为此,请使用
for(A a : set) { visit(a); }
我碰到的情况下,我真的想要一个索引访问分类集(我赞同其他海报访问一个索引没有意义的未分类的集合)。 一个例子就是一棵树,我希望孩子被sorting,重复的孩子不被允许。
我需要通过索引访问来显示它们,设置的属性派上用场,有效地消除重复。
在java.util或Google集合中找不到合适的集合,我发现直接自己实现它。 基本的想法是包装一个SortedSet并在需要通过索引进行访问时创build一个List(当SortedSet被改变时忘记列表)。 当然,这当然只能在更改包装的SortedSet时有效地工作,并且在Collection的生命周期中访问列表是分开的。 否则,它的行为就像一个经常sorting的列表,即太慢了。
有了大量的孩子,这种改进的性能比我通过Collections.sortsorting的列表更多。
请注意,只有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)
方法。
你可以做new ArrayList<T>(set).get(index)
Set 接口没有获得索引types的调用,甚至更基本的原因,如first()或last(),是因为它是一个模糊的操作,因此是一个潜在的危险操作。 如果一个方法返回一个Set,并且你调用First()方法,那么预期的结果是什么,因为一个通用Set对sorting没有任何保证。 由此产生的对象在每次调用方法之间可能会有所不同,或者它可能不会让您陷入错误的安全感,直到您使用更改的库更改了下面的实现,现在您发现所有代码都会中断没有特别的原因。
这里列出的解决方法的build议是很好的。 如果您需要索引访问,请使用列表。 在使用迭代器或toArray时要小心使用generics集合,因为a)不能保证sorting和b)不能保证sorting不会随后续的调用或不同的基础实现而改变。 如果你需要中间的东西,SortedSet或LinkedHashSet是你想要的。
//我希望Set接口有一个get-random-element。
java.util.Set
是无序项目的集合。 如果Set有一个get(int index),没有任何意义,因为Set没有索引,你也只能猜测这个值。
如果你真的想这样做,编写一个方法来从Set中获得随机元素。
如果您不介意要sorting的集合,那么您可能有兴趣查看索引树映射项目。
增强的TreeSet / TreeMap提供通过索引访问元素或获取元素的索引。 并且实现基于更新RB树中的节点权重。 所以在这里没有迭代或备份列表。
为了得到一个集合中的元素,我使用以下一个:
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; }