如何在没有迭代的情况下获取给定LinkedHashSet元素的索引?

它甚至可能吗?

说你有

private Set names = new LinkedHashSet(); 

Strings是“迈克”,“约翰”,“凯伦”。

是否有可能在没有迭代的情况下得到“1”以回答“约翰”的索引是什么?

以下工作正常..有了这个问题,我想知道是否有更好的方法

 for (String s : names) { ++i; if (s.equals(someRandomInputString)) { break; } } 

Set接口没有像indexOf()方法那样的东西。 你真的需要迭代它或者使用List接口代替它提供indexOf()方法 。

如果你愿意,将Set转换为List是非常简单的,它应该是通过List实现的构造函数传递Set的问题。 例如

 List nameList = new ArrayList(nameSet); // ... 

这是一个执行插入,删除,保留,由arraylist支持在get(index)上实现o(1)的实现。

 /** * @Author Mo. Joseph * * Allows you to call get with o(1) instead of o(n) to get an instance by index */ public static final class $IndexLinkedHashSet extends LinkedHashSet { private final ArrayList list = new ArrayList<>(); public $IndexLinkedHashSet(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); } public $IndexLinkedHashSet() { super(); } public $IndexLinkedHashSet(int initialCapacity) { super(initialCapacity); } public $IndexLinkedHashSet(Collection c) { super(c); } @Override public synchronized boolean add(E e) { if ( super.add(e) ) { return list.add(e); } return false; } @Override public synchronized boolean remove(Object o) { if ( super.remove(o) ) { return list.remove(o); } return false; } @Override public synchronized void clear() { super.clear(); list.clear(); } public synchronized E get(int index) { return list.get(index); } @Override public synchronized boolean removeAll(Collection c) { if ( super.removeAll(c) ) { return list.removeAll(c); } return true; } @Override public synchronized boolean retainAll(Collection c) { if ( super.retainAll(c) ) { return list.retainAll(c); } return false; } /** * Copied from super class */ @Override public synchronized boolean addAll(Collection c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } } 

测试它:

 public static void main(String[] args) { $IndexLinkedHashSet abc = new $IndexLinkedHashSet(); abc.add("8"); abc.add("8"); abc.add("8"); abc.add("2"); abc.add("3"); abc.add("4"); abc.add("1"); abc.add("5"); abc.add("8"); System.out.println("Size: " + abc.size()); int i = 0; while ( i < abc.size()) { System.out.println( abc.get(i) ); i++; } abc.remove("8"); abc.remove("5"); System.out.println("Size: " + abc.size()); i = 0; while ( i < abc.size()) { System.out.println( abc.get(i) ); i++; } abc.clear(); System.out.println("Size: " + abc.size()); i = 0; while ( i < abc.size()) { System.out.println( abc.get(i) ); i++; } } 

哪个输出:

 Size: 6 8 2 3 4 1 5 Size: 4 2 3 4 1 Size: 0 

Ofcourse remove,removeAll,retainAll现在具有与ArrayList相同或更差的性能。 但是我不使用它们,所以我对此感到满意。

请享用!

编辑:

这是另一个实现 ,它不扩展LinkedHashSet,因为这是多余的。 相反,它使用HashSet和ArrayList。

 /** * @Author Mo. Joseph * * Allows you to call get with o(1) instead of o(n) to get an instance by index */ public static final class $IndexLinkedHashSet implements Set { private final ArrayList list = new ArrayList<>( ); private final HashSet set = new HashSet<> ( ); public synchronized boolean add(E e) { if ( set.add(e) ) { return list.add(e); } return false; } public synchronized boolean remove(Object o) { if ( set.remove(o) ) { return list.remove(o); } return false; } @Override public boolean containsAll(Collection c) { return set.containsAll(c); } public synchronized void clear() { set.clear(); list.clear(); } public synchronized E get(int index) { return list.get(index); } public synchronized boolean removeAll(Collection c) { if ( set.removeAll(c) ) { return list.removeAll(c); } return true; } public synchronized boolean retainAll(Collection c) { if ( set.retainAll(c) ) { return list.retainAll(c); } return false; } public synchronized boolean addAll(Collection c) { boolean modified = false; for (E e : c) if (add(e)) modified = true; return modified; } @Override public synchronized int size() { return set.size(); } @Override public synchronized boolean isEmpty() { return set.isEmpty(); } @Override public synchronized boolean contains(Object o) { return set.contains(o); } @Override public synchronized Iterator iterator() { return list.iterator(); } @Override public synchronized Object[] toArray() { return list.toArray(); } @Override public synchronized  T[] toArray(T[] a) { return list.toArray(a); } } 

现在你有两个实现,我更喜欢第二个。

我不相信,但您可以创建一个LinkedHashSetWithIndex包装类,它将为您进行迭代,或者如果性能降低对于您的用例可接受,则保留一个包含每个条目的索引的单独表。

虽然不如机器效率高,但它可以在一条线上实现:

 int index = new ArrayList(names).indexOf("John"); 

Set通常不可能返回索引,因为它不一定为特定的Set实现定义良好。 例如,它在HashSet文档中说

它不保证集合的迭代顺序; 特别是,它不保证订单会随着时间的推移保持不变。

因此,当您实际期望的是Set实现som顺序时,您不应该说类型是Set。

Set是“不包含重复元素的集合”,并且它不维护其元素的顺序。 http://download.oracle.com/javase/6/docs/api/java/util/Set.html

您提供的代码不一定每次都返回1。 迭代通过Set不能保证每次都以相同的顺序迭代; 它只能保证迭代每个元素一次。

由于您似乎关心元素的顺序,因此您需要使用List而不是Set

没有更好的方法,只有一个有衬里的(也使用迭代器,但是隐式):

 new ArrayList(names).get(0)