web-dev-qa-db-de.com

Ir die Implementierung des bestellten Sets in Java?

Wenn jemand mit Objective-C vertraut ist, gibt es eine Sammlung mit dem Namen NSOrderedSet , die als Set fungiert, und auf deren Elemente kann als Array zugegriffen werden.

Gibt es so etwas in Java?

Ich habe gehört, dass es eine Sammlung mit dem Namen LinkedHashMap gibt, aber ich habe nichts dergleichen für einen Satz gefunden.

85
Uko

Werfen Sie einen Blick auf LinkedHashSet class

102
Chandra Sekhar

Jedes Set hat einen Iterator (). Ein normaler HashSet-Iterator ist ziemlich zufällig, ein TreeSet führt die Sortierung durch, ein LinkedHashSet Iterator durchläuft die Insert-Reihenfolge.

Sie können ein Element in einem LinkedHashSet jedoch nicht ersetzen. Sie können eines entfernen und ein anderes hinzufügen, das neue Element wird jedoch nicht an die Stelle des Originals gesetzt. In einer LinkedHashMap können Sie einen Wert für einen vorhandenen Schlüssel ersetzen. Die Werte bleiben dann in der ursprünglichen Reihenfolge.

Sie können auch nicht an einer bestimmten Position einfügen.

Vielleicht sollten Sie eine ArrayList mit einer expliziten Prüfung verwenden, um das Einfügen von Duplikaten zu vermeiden.

29
Geert Pante

Schauen Sie sich die Java Standard API doc an. Gleich neben LinkedHashMap gibt es eine LinkedHashSet . Beachten Sie jedoch, dass die Reihenfolge darin die Einfügereihenfolge ist, nicht die natürliche Reihenfolge der Elemente. Sie können nur in dieser Reihenfolge iterieren und keinen wahlfreien Zugriff durchführen (außer durch das Zählen von Iterationsschritten).

Es gibt auch eine Schnittstelle SortedSet , die von TreeSet und ConcurrentSkipListSet implementiert wird. Beide erlauben eine Iteration in der natürlichen Reihenfolge ihrer Elemente oder einer Comparator , jedoch nicht die Direktzugriffs- oder Einfügungsreihenfolge.

Für eine Datenstruktur, die sowohl über einen effizienten Zugriff nach Index verfügt als auch das gesetzte Kriterium effizient implementieren kann, benötigen Sie eine Liste überspringen , aber es gibt keine Implementierung dieser Funktionalität in der Java-Standard-API leicht im Internet zu finden.

8
4
Mike Yockey

Versuchen Sie es mit Java.util.TreeSet , das SortedSet implementiert.

So zitieren Sie das Dokument:

"Die Elemente werden nach ihrer natürlichen Reihenfolge oder mit einem Komparator angeordnet, der zum festgelegten Erstellungszeitpunkt bereitgestellt wird, abhängig davon, welcher Konstruktor verwendet wird."

Beachten Sie, dass Hinzufügen, Entfernen und Enthalten ein Zeitkostenprotokoll (n) enthält. 

Wenn Sie auf den Inhalt des Satzes als Array zugreifen möchten, können Sie ihn folgendermaßen konvertieren:

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

Dieses Array wird nach denselben Kriterien wie das TreeSet (natürlich oder durch einen Vergleicher) sortiert, und in vielen Fällen hat dies einen Vorteil, anstatt Arrays.sort () auszuführen.

4

treeset ist eine geordnete Menge, auf die Sie jedoch nicht über einen Artikelindex zugreifen können.

1
NimChimpsky

Möglicherweise erhalten Sie auch ein Hilfsprogramm aus einer bidirektionalen Karte wie die BiMap aus Google Guava .

Mit einer BiMap können Sie eine Ganzzahl (für den Zufallsindexzugriff) ziemlich effizient jedem anderen Objekttyp zuordnen. BiMaps sind Eins-zu-Eins, also ist jeder gegebenen Ganzzahl höchstens ein Element zugeordnet, und jedem Element ist eine Ganzzahl zugeordnet. Es wird geschickt von zwei HashTable-Instanzen untermauert, so dass fast der doppelte Speicherplatz verbraucht wird, aber es ist wesentlich effizienter als eine benutzerdefinierte List-Verarbeitung, da contains() (das aufgerufen wird, wenn ein Element hinzugefügt wird, um zu prüfen, ob es bereits existiert) Konstante Zeit und parallel-freundlicher Betrieb wie HashSet, während die Implementierung von List viel langsamer ist.

0
Steve K

Wenn wir über die kostengünstige Implementierung der Auslassungsliste sprechen, frage ich mich in Bezug auf big O, was die Kosten für diese Operation sind:

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

Ich meine, es bleibt immer in einer ganzen Array-Erstellung hängen, also ist es O (n): 

Java.util.Arrays#copyOf
0
acridity

IndexedTreeSet aus dem indexed-tree-map project bietet diese Funktionalität (geordnetes/sortiertes Set mit listeartigem Zugriff nach Index).

0

Ich hatte ein ähnliches Problem. Ich brauchte kein ordentliches Set, sondern eher eine Liste mit einem schnellen indexOf/contains. Da ich dort nichts gefunden habe, habe ich selbst eines implementiert. Hier ist der Code, der sowohl Set als auch List implementiert, obwohl nicht alle Massenlistenoperationen so schnell sind wie die Versionen von ArrayList.

Haftungsausschluss: nicht getestet

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