Bei einem einfachen Set<T>
, was ist ein guter Weg (schnell, wenige Zeilen Code) zu bekommen jeden Wert aus dem Set
?
Mit a List
ist es einfach:
List<T> things = ...;
return things.get(0);
Aber mit a Set
gibt es keine .get(...)
Methode, weil Set
s nicht geordnet sind.
iterator().next()
. (Deshalb haben wir keinegetFirst(Iterable<E>)
, nur einegetFirst(Iterable<E>, E default)
.)Set
mir bekannte Implementierung ist dies höchstens O (log n).LinkedHashSet
.)Da Streams vorhanden sind, können Sie dies auch so tun, aber Sie müssen die Klasse verwenden
java.util.Optional
.Optional
ist eine Wrapper-Klasse für ein Element oder explizit kein Element (unter Vermeidung des Nullzeigers).//returns an Optional. Optional <T> optT = set.stream().findAny(); //Optional.isPresent() yields false, if set was empty, avoiding NullpointerException if(optT.isPresent()){ //Optional.get() returns the actual element return optT.get(); }
Bearbeiten: Wie ich es selbst
Optional
ziemlich oft benutze : Es gibt eine Möglichkeit, auf das Element zuzugreifen oder eine Standardeinstellung zu erhalten, falls es nicht vorhanden ist:optT.orElse(other)
Gibt entweder das Element zurück oder, falls nicht vorhandenother
,.other
kannnull
übrigens sein.quelle
set.iterator().next();
.Das Abrufen eines Elements aus einem Satz oder einer Sammlung mag als ungewöhnliche Anforderung erscheinen - wenn auch nicht willkürlich oder vielseitig -, ist jedoch durchaus üblich, wenn beispielsweise Statistiken für Schlüssel- oder Werteobjekte in einer Karte berechnet und min / initialisiert werden müssen. Maximalwerte . Das beliebige Element aus einem Set / einer Sammlung (von Map.keySet () oder Map.values () zurückgegeben) wird für diese Initialisierung verwendet, bevor die Min / Max-Werte jeweils aktualisiert werden Element .
Welche Möglichkeiten hat man also, wenn man mit diesem Problem konfrontiert wird und gleichzeitig versucht, Speicher und Ausführungszeit klein und Code klar zu halten?
Oft erhalten Sie das Übliche: " Set in ArrayList konvertieren und das erste Element erhalten ". Großartig! Ein weiteres Array mit Millionen von Elementen und zusätzlichen Verarbeitungszyklen zum Abrufen von Objekten aus Set, Zuweisen eines Arrays und Auffüllen :
HashMap<K,V> map; List<K> list = new ArrayList<V>(map.keySet()); // min/max of keys min = max = list.get(0).some_property(); // initialisation step for(i=list.size();i-->1;){ if( min > list.get(i).some_property() ){ ... } ... }
Oder man kann eine Schleife mit einem Iterator verwenden, wobei ein Flag verwendet wird, um anzuzeigen, dass min / max initialisiert werden muss, und eine bedingte Anweisung, um zu überprüfen, ob dieses Flag für alle Iterationen in der Schleife gesetzt ist. Dies impliziert eine Menge bedingter Überprüfungen.
boolean flag = true; Iterator it = map.keySet().iterator(); while( it.hasNext() ){ if( flag ){ // initialisation step min = max = it.next().some_property(); flag = false; } else { if( min > list.get(i).some_property() ){ min = list.get(i).some_property() } ... } }
Oder führen Sie die Initialisierung außerhalb der Schleife durch:
HashMap<K,V> map; Iterator it = map.keySet().iterator(); K akey; if( it.hasNext() ){ // initialisation step: akey = it.next(); min = max = akey.value(); do { if( min > list.get(i).some_property() ){ min = akey.some_property() } } while( it.hasNext() && ((akey=it.next())!=null) ); }
Aber ist es das ganze Manöver im Namen des Programmierers (und des Einrichtens des Iterators im Auftrag der JVM) wirklich wert, wann immer Min / Max benötigt werden?
Der Vorschlag eines javally-korrekten alten Sports könnte lauten: "Wickeln Sie Ihre Karte in eine Klasse ein, die die Min- und Max-Werte beim Setzen oder Löschen verfolgt!"
Es gibt eine andere Situation , in der meiner Erfahrung nach nur ein beliebiger Gegenstand aus einer Karte benötigt wird. In diesem Fall enthält die Karte Objekte, die eine gemeinsame Eigenschaft haben - für alle in dieser Karte gleich - und Sie müssen diese Eigenschaft lesen . Angenommen, es gibt eine Karte mit Aufbewahrungsfächern desselben Histogramms mit derselben Anzahl von Dimensionen. Bei einer solchen Karte müssen Sie möglicherweise die Anzahl der Dimensionen eines beliebigen Histobins in der Karte kennen, um beispielsweise einen weiteren Histobin mit denselben Dimensionen erstellen zu können. Muss ich einen Iterator erneut einrichten und entsorgen, nachdem ich next () nur einmal aufgerufen habe? Ich werde den Vorschlag der javally-korrekten Person zu dieser Situation überspringen.
Und wenn all die Mühe , die in immer jedes Element verursacht unbedeutend Speicher und CPU - Zyklen zu erhöhen, was ist dann mit all dem Code zu schreiben hat gerade das schwer zu bekommen zu bekommen jedes Element.
Wir brauchen das beliebige Element. Gib es uns!
quelle