2013-07-11 9 views
7

Da Set-Einträge nur durch eine Teilmenge von Eigenschaften unterschieden werden (hashCode() + equals()), ist es manchmal notwendig, das Originalobjekt in einem Set zu bearbeiten, was mit java.util.Set nicht möglich ist. Die einzige Alternative, die ich gefunden habe, ist: Map<T, T> - keine sehr übersichtliche Lösung.Warum java.util.Set enthält keinen Wert Getter? Gibt es Alternativen dazu?

Gibt es im Sammelrahmen noch weitere Alternativen? Anforderungen sind: O (1) Abrufzeit und keine Duplikate basierend auf hashCode() + equals() Ergebnis.

+0

Suchen Sie nach [HashSet] (http://docs.oracle.com/javase/7/docs/api/java/util/HashSet.html)? –

+0

Ah, also willst du das Originalobjekt aus dem Set. Nun, der einfachste Weg wäre Ihre Map Lösung. Gibt es einen Grund, warum es nicht sehr praktisch ist? – Kayaman

+0

@Kayaman - rechts, fest – Marcin

Antwort

0

Nicht in java.util.Collections selbst, aber unter Verwendung Google Guava können Sie jedes Element aus einer gegebenen Iterator mit Iterables.get abrufen.

Normalerweise würde ich keine externen Bibliotheken befürworten, aber angesichts der extrem mächtigen und nützlichen Guava sehe ich kein Problem damit.

Alternativ können Sie das Set auch mit Ihrer eigenen Implementierung iterieren.


Zusätzlich fand ich ein sehr interessantes thread hier, dass dieses Verhalten erklärt.

+3

Aber es wäre nicht mehr O (1). – Kayaman

0

kann A Set enthält keine zwei Objekte o1 und o2 so dass o1.equals(o2) (Nr hashCode in diesen Kriterien verwendet wird).

Eine HashSet verwendet eine Hashmap, um ihre Objekte effizient zu speichern, so dass schließlich eine HashMap genau das ist, was Sie für hashCode()+equals() basierte Operationen benötigen.

+0

Das ist nicht das, wonach er fragt: Er möchte ein Objekt aus einer Menge abrufen, die einem anderen Objekt in konstanter Zeit "gleicht". – arshajii

+1

@arshajii Ich verstehe das, aber die Set-Schnittstelle bietet keine Methode zum Abrufen von Objekten und es ist wahrscheinlich, da dies nicht die Absicht eines Sets ist. Seine Anforderung, Objekte mit Hilfe ihres Hashcodes und ihres Gleichstands effizient zu unterscheiden, ist genau das, wofür Hash Maps steht. – giorashc

+0

Du sagst also, er sollte eine 'Map ' verwenden, wie er es schon versucht hat? – arshajii

0

Ich schrieb eine solche Klasse, wenn Sie sie wiederverwenden wollen. Jayes enthält eine Klasse org.eclipse.recommenders.jayes.util.sharing.CanonicalSet, die den Abruf basierend auf so ziemlich jeder Äquivalenzrelation ermöglicht, die Sie in einer hashCode()- und equals()-Implementierung codieren können. Ich habe es verwendet, um Array-Äquivalenzklassen zu erstellen. Sie können diese Implementierungen von CanonicalSet betrachten, sie sind im selben Paket.

Oh, aber ja, es basiert auch nur auf einem Map<Entry<T>,T>, also nichts Magisches wirklich.

0

Der Code für eine HashSet auf einem HashMap basiert ist super einfach: wenn man sich die Art und Weise sehen sie in der JDK implementiert ist, gibt es nur sehr wenige Zeilen tatsächlichen Code (die Konstrukteure und die serialiazation Code ignoriert wird).

Auf Art und Weise, es zu tun wäre, um Ihre eigene Version von HashSet mit der zusätzlichen get() Methode zu implementieren

public E get(Object o) { 
    return map.get(o); 
} 
0

Ja, es ist ein bisschen Schmerz, nicht in der Lage teilen gleiche Objekte.Das Problem mit dem Set-API ist, dass ther eine spezifische addAndGet fehlt:

AddOnceSet<String> set = new AddOnceSet<>(); 
String s = in.readLine(); 
s = set.addOnce(s); // The new s is equal, and identical to the first added one. 

s = set.getOnce(s); 

Leider ist dies nicht die Sammlungen API paßt. Ich wünschte, dies könnte in Java 8+ sein. In Java 8 können Sie eine Schnittstelle mit Standardwerten für addOnce und getOnce hinzufügen.

Implementation wie Sie gesagt, in:

private Map<T, T> sharedThings = new HashMap<>(). 

public T shareThing(T s) { 
    String t = sharedThings.get(s); 
    if (t == null) { 
     t = s; 
     sharedStrings.put(t, t); 
    } 
    return t; 
} 

... 

public void setT(T t) { 
    this.t = sharedThing(t); 
} 
2

Wenn man mehr O (1) Betrieb nicht Problem ist, können Sie Methode Fernbleiben simulieren get(Object) mit zwei Methoden set.remove(Object) und set.add(Object). Andernfalls würde ich Map<T,T> wie Sie erwähnten oder einfach Wrapper-Klasse mit zugrunde liegenden Karte verwenden.

EDIT: Der Grund, warum Set nicht get(Object) enthält, ist, dass Sie nicht Objekt zurückgeben müssen, die Sie kennen. Sie müssen nur überprüfen, ob Ihr Objekt im Set enthalten ist oder nicht.

Verwandte Themen