web-dev-qa-db-fra.com

Toute implémentation de Ordered Set en Java?

Si quelqu'un connaît Objective-C, il existe une collection appelée NSOrderedSet qui agit comme Set et ses éléments sont accessibles en tant que ceux de Array.

Y at-il quelque chose comme ça en Java?

J'ai entendu dire qu'il existe une collection appelée LinkedHashMap , mais je n'ai rien trouvé de tel pour un ensemble.

85
Uko

Jetez un oeil à LinkedHashSet class

102
Chandra Sekhar

Chaque ensemble a un itérateur (). L'itérateur d'un HashSet normal est assez aléatoire, un TreeSet le fait par ordre de tri, un LinkedHashSet iterator itère par ordre d'insertion.

Cependant, vous ne pouvez pas remplacer un élément dans un LinkedHashSet. Vous pouvez en supprimer un et en ajouter un autre, mais le nouvel élément ne sera pas à la place de l'original. Dans un LinkedHashMap, vous pouvez remplacer une valeur pour une clé existante, puis les valeurs seront toujours dans l'ordre d'origine.

En outre, vous ne pouvez pas insérer à une certaine position.

Vous feriez peut-être mieux d'utiliser un ArrayList avec une vérification explicite pour éviter d'insérer des doublons.

29
Geert Pante

Jetez un coup d’œil au doc API standard Java . Juste à côté de LinkedHashMap , il y a un LinkedHashSet . Mais notez que l'ordre dans ceux-ci est l'ordre d'insertion, pas l'ordre naturel des éléments. Et vous ne pouvez qu'itérer dans cet ordre, pas d'accès aléatoire (sauf en comptant les étapes d'itération).

Il existe également une interface SortedSet implémentée par TreeSet et ConcurrentSkipListSet . Les deux autorisent l’itération dans l’ordre naturel de leurs éléments ou a Comparator , mais pas dans un accès aléatoire ni dans un ordre d’insertion.

Pour une structure de données ayant à la fois un accès efficace par index et pouvant implémenter efficacement le critère défini, vous aurez besoin d'une liste de sauts , mais cette fonctionnalité n'est pas implémentée dans l'API standard Java facile à trouver sur internet.

8
Michael Borgwardt
4
Mike Yockey

Essayez d’utiliser Java.util.TreeSet qui implémente SortedSet .

Pour citer le doc:

"Les éléments sont classés en utilisant leur ordre naturel, ou par un comparateur fourni au moment de la création du jeu, en fonction du constructeur utilisé"

Notez que ajouter, supprimer et contient un journal de coût en temps (n). 

Si vous souhaitez accéder au contenu de l'ensemble sous forme de tableau, vous pouvez le convertir en procédant comme suit:

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

Ce tableau sera trié avec les mêmes critères que TreeSet (naturel ou par un comparateur), ce qui aura souvent un avantage au lieu de faire un Arrays.sort ()

4
Thomas Johan Eggum

treeset est un ensemble ordonné, mais vous ne pouvez pas y accéder via un index d'éléments, il vous suffit de parcourir ou d'aller au début/à la fin.

1
NimChimpsky

Vous pouvez également obtenir un utilitaire dans une carte bidirectionnelle telle que le BiMap from Google Guava

Avec un BiMap, vous pouvez très efficacement mapper un Integer (pour un accès aléatoire à un index) à tout autre type d'objet. BiMaps sont un-à-un, donc tout entier donné a au plus un élément qui lui est associé et tout élément a un entier associé. Il repose intelligemment sur deux instances HashTable. Il utilise donc presque le double de mémoire, mais il est beaucoup plus efficace qu'une List personnalisée dans la mesure où il est traité car contains() (qui est appelé lorsqu'un élément est ajouté existe) est une opération à temps constant et conviviale en parallèle comme celle de HashSet, alors que la mise en oeuvre de List est BEAUCOUP plus lente.

0
Steve K

Si nous parlons d'une mise en oeuvre peu coûteuse de la liste de sauts, je me demande en termes de gros O, quel est le coût de cette opération

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

Je veux dire qu'il est toujours bloqué dans la création d'un tableau entier, c'est donc O (n): 

Java.util.Arrays#copyOf
0
acridity

IndexedTreeSet à partir du indexed-tree-map project fournit cette fonctionnalité (ensemble trié/trié avec accès par index semblable à une liste).

0
Vitaly Sazanovich

J'avais un problème similaire. Je n'avais pas vraiment besoin d'un ensemble ordonné mais plutôt d'une liste avec une variable indexOf/contains rapide. Comme je n'ai rien trouvé là-bas, j'en ai mis en place un moi-même. Voici le code, il implémente Set et List, bien que toutes les opérations de liste en bloc ne soient pas aussi rapides que les versions ArrayList.

disclaimer: non testé

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