web-dev-qa-db-ja.com

JavaでのOrdered Setの実装はありますか?

誰かがObjective-Cに精通している場合、 NSOrderedSet と呼ばれるコレクションがあり、Setとして機能し、そのアイテムには次のようにアクセスできますArrayの配列。

Javaにはこのようなものがありますか?

LinkedHashMap と呼ばれるコレクションがあると聞いたことがありますが、セット用にそのようなものは見つかりませんでした。

87
Uko

LinkedHashSet classを見てください

105
Chandra Sekhar

すべてのセットにはiterator()があります。通常のHashSetの反復子は非常にランダムで、TreeSetはソート順で実行します。 LinkedHashSet 反復子は挿入順で反復します。

ただし、LinkedHashSetの要素を置き換えることはできません。あるものを削除して別の要素を追加することはできますが、新しい要素は元の場所にありません。 LinkedHashMapでは、既存のキーの値を置き換えることができますが、値は元の順序のままです。

また、特定の位置に挿入することはできません。

たぶん、重複の挿入を避けるために、明示的なチェックでArrayListを使用した方が良いでしょう。

30
Geert Pante

Java標準APIドキュメント をご覧ください。 LinkedHashMap のすぐ隣に LinkedHashSet があります。ただし、それらの順序は挿入順序であり、要素の自然な順序ではないことに注意してください。そして、その順序でのみ反復でき、ランダムアクセスはできません(反復ステップをカウントする場合を除く)。

インターフェイスもあります SortedSetTreeSet および ConcurrentSkipListSet によって実装されています。どちらも、要素の 自然順序 または Comparator での反復を許可しますが、ランダムアクセスまたは挿入の順序は許可しません。

インデックスによる効率的なアクセスと、設定基準の効率的な実装の両方が可能なデータ構造の場合、 スキップリスト が必要ですが、Javaにはその機能を実装するものはありません。 _標準API。ただし、インターネットで簡単に見つけることができます。

10
4
Mike Yockey

Java.util.TreeSet を実装する SortedSet を使用してみてください。

ドキュメントを引用するには:

「要素は、使用されるコンストラクタに応じて、自然な順序付けを使用して、またはセット作成時に提供されるコンパレータによって順序付けられます」

追加、削除、および包含には時間コストlog(n)があることに注意してください。

セットのコンテンツに配列としてアクセスする場合は、次のようにして変換できます。

YourType[] array = someSet.toArray(new YourType[yourSet.size()]); 

この配列は、TreeSetと同じ基準(自然またはコンパレーター)でソートされ、多くの場合、Arrays.sort()を実行する代わりに利点があります。

4

treeset は順序付けられたセットですが、アイテムインデックスを介してアクセスすることはできません。繰り返しまたは先頭/末尾に移動するだけです。

1
NimChimpsky

BiMap from Google Guava のような双方向マップからユーティリティを取得することもできます

BiMapを使用すると、整数(ランダムインデックスアクセス用)を他のオブジェクトタイプに非常に効率的にマップできます。 BiMapsは1対1であるため、指定された整数には最大で1つの要素が関連付けられ、要素には整数が1つ関連付けられます。 2つのHashTableインスタンスによって巧妙に支えられているため、ほぼ2倍のメモリを使用しますが、_contains()(アイテムが追加されたときに呼び出されて既にチェックされているため、カスタムのListが存在します)は、HashSetのような一定時間で並列処理に適した操作ですが、Listの実装はLOTより低速です。

0
Steve K

スキップリストの安価な実装について話している場合、この操作のコストは何ですか?

YourType [] array = someSet.toArray(new YourType [yourSet.size()]);

つまり、常に配列全体の作成にこだわるので、O(n)です。

Java.util.Arrays#copyOf
0
acridity

IndexedTreeSet from indexed-tree-map プロジェクトは、この機能を提供します(インデックスによるリストのようなアクセスを備えた順序付け/ソートされたセット)。

0

同様の問題がありました。順序付けられたセットは必要ありませんでしたが、高速のindexOf/containsのリストが必要です。そこに何も見つからなかったので、自分で実装しました。コードは次のとおりです。SetListの両方を実装していますが、すべての一括リスト操作がArrayListバージョンほど高速ではありません。

免責事項:未テスト

import Java.util.ArrayList;
import Java.util.HashMap;
import Java.util.Set;
import Java.util.Collection;
import Java.util.Comparator;
import Java.util.function.Predicate;
import Java.util.function.UnaryOperator;
import static Java.util.Objects.requireNonNull;

/**
 * An ArrayList that keeps an index of its content so that contains()/indexOf() are fast. Duplicate entries are
 * ignored as most other Java Set's do.
 */
public class IndexedArraySet<E> extends ArrayList<E> implements Set<E> {

    public IndexedArraySet() { super(); }

    public IndexedArraySet(Iterable<E> c) {
        super();
        addAll(c);
    }

    private HashMap<E, Integer> indexMap = new HashMap<>();

    private void reindex() {
        indexMap.clear();
        int idx = 0;
        for (E item: this) {
            addToIndex(item, idx++);
        }
    }

    private E addToIndex(E e, int idx) {
        indexMap.putIfAbsent(requireNonNull(e), idx);
        return e;
    }

    @Override
    public boolean add(E e) {
        if(indexMap.putIfAbsent(requireNonNull(e), size()) != null) return false;
        super.add(e);
        return true;
    }

    @Override
    public boolean addAll(Collection<? extends E> c) {
        return addAll((Iterable<? extends E>) c);
    }
    public boolean addAll(Iterable<? extends E> c) {
        boolean rv = false;
        for (E item: c) {
            rv |= add(item);
        }
        return rv;
    }

    @Override
    public boolean contains(Object e) {
        return indexMap.containsKey(e);
    }

    @Override

    public int indexOf(Object e) {
        if (e == null) return -1;
        Integer i = indexMap.get(e);
        return (i == null) ? -1 : i;
    }

    @Override
    public int lastIndexOf(Object e) {
        return indexOf(e);
    }

    @Override @SuppressWarnings("unchecked")
    public Object clone() {
        IndexedArraySet clone = (IndexedArraySet) super.clone();
        clone.indexMap = (HashMap) indexMap.clone();
        return clone;
    }

    @Override
    public void add(int idx, E e) {
        if(indexMap.putIfAbsent(requireNonNull(e), -1) != null) return;
        super.add(idx, e);
        reindex();
    }

    @Override
    public boolean remove(Object e) {
        boolean rv;
        try { rv = super.remove(e); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public void clear() {
        super.clear();
        indexMap.clear();
    }

    @Override
    public boolean addAll(int idx, Collection<? extends E> c) {
        boolean rv;
        try {
            for(E item : c) {
                // check uniqueness
                addToIndex(item, -1);
            }
            rv = super.addAll(idx, c);
        } finally {
            reindex();
        }
        return rv;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        boolean rv;
        try { rv = super.removeAll(c); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        boolean rv;
        try { rv = super.retainAll(c); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public boolean removeIf(Predicate<? super E> filter) {
        boolean rv;
        try { rv = super.removeIf(filter); }
        finally { reindex(); }
        return rv;
    }

    @Override
    public void replaceAll(final UnaryOperator<E> operator) {
        indexMap.clear();
        try {
            int duplicates = 0;
            for (int i = 0; i < size(); i++) {
                E newval = requireNonNull(operator.apply(this.get(i)));
                if(indexMap.putIfAbsent(newval, i-duplicates) == null) {
                    super.set(i-duplicates, newval);
                } else {
                    duplicates++;
                }
            }
            removeRange(size()-duplicates, size());
        } catch (Exception ex) {
            // If there's an exception the indexMap will be inconsistent
            reindex();
            throw ex;
        }

    }

    @Override
    public void sort(Comparator<? super E> c) {
        try { super.sort(c); }
        finally { reindex(); }
    }
}
0
JanKanis