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

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在没有迭代的情况下获取给定LinkedHashSet元素的索引?相关的知识,希望对你有一定的参考价值。

它甚至可能吗?

说你有

private Set<String> names = new LinkedHashSet<String>();

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

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

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

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

Set interface没有像indexOf()方法那样的东西。你真的需要迭代它或使用List interface而不是提供indexOf() method

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

List<String> nameList = new ArrayList<String>(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<E> extends LinkedHashSet<E> {
        private final ArrayList<E> list = new ArrayList<>();

        public $IndexLinkedHashSet(int initialCapacity, float loadFactor) {
                super(initialCapacity, loadFactor);
        }
        public $IndexLinkedHashSet() {
                super();
        }
        public $IndexLinkedHashSet(int initialCapacity) {
                super(initialCapacity);
        }
        public $IndexLinkedHashSet(Collection<? extends E> 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<? extends E> c) {
                boolean modified = false;
                for (E e : c)
                        if (add(e))
                                modified = true;
                return modified;
        }

}

测试它:

public static void main(String[] args) {

        $IndexLinkedHashSet<String> abc = new $IndexLinkedHashSet<String>();
        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<E> implements Set<E> {
        private final ArrayList<E> list = new ArrayList<>( );
        private final HashSet<E>   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<? extends E> 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<E> iterator() {
                return list.iterator();
        }

        @Override
        public synchronized Object[] toArray() {
                return list.toArray();
        }

        @Override
        public synchronized <T> T[] toArray(T[] a) {
                return list.toArray(a);
        }
}

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

另一答案

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

另一答案

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

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

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

另一答案

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

int index = new ArrayList<String>(names).indexOf("John");
另一答案

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

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

因为你似乎关心元素的顺序,你需要使用List而不是Set

另一答案

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

new ArrayList(names).get(0)

以上是关于如何在没有迭代的情况下获取给定LinkedHashSet元素的索引?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不复制的情况下从 N 维容器中获取可迭代范围?

如何在没有继承方法的情况下获取类的公共方法?

如何在给定进程名称的情况下获取 pid

Groovy - 如何在不更新地图的情况下使用默认值获取地图值

如何在给定上下文的情况下获取布局充气器?

如何在给定时间和状态信息的情况下获取当地时区