Tre risposte a 1 riga ...
Vorrei utilizzare Google Collections Guava per fare questo - se i tuoi valori sono Comparable
allora puoi usare
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map))
Che creerà una funzione (oggetto) per la mappa [che accetta una qualsiasi delle chiavi come input, restituendo il rispettivo valore], e quindi applica loro l'ordine naturale (comparabile) [i valori].
Se non sono comparabili, allora dovrai fare qualcosa del genere
valueComparator = Ordering.from(comparator).onResultOf(Functions.forMap(map))
Questi possono essere applicati a una TreeMap (come Ordering
estesa Comparator
) o a LinkedHashMap dopo un certo ordinamento
NB : Se hai intenzione di utilizzare una TreeMap, ricorda che se un confronto == 0, l'elemento è già nell'elenco (cosa che succederà se hai più valori che confrontano lo stesso). Per alleviare questo, puoi aggiungere la tua chiave al comparatore in questo modo (presumendo che le tue chiavi e i tuoi valori siano Comparable
):
valueComparator = Ordering.natural().onResultOf(Functions.forMap(map)).compound(Ordering.natural())
= Applica l'ordinamento naturale al valore mappato dalla chiave e mescola quello con l'ordinamento naturale della chiave
Nota che questo non funzionerà ancora se le tue chiavi sono pari a 0, ma questo dovrebbe essere sufficiente per la maggior parte degli comparable
elementi (come hashCode
, equals
e compareTo
spesso sono sincronizzati ...)
Vedere Ordering.onResultOf () e Functions.forMap () .
Implementazione
Quindi ora che abbiamo un comparatore che fa quello che vogliamo, dobbiamo ottenere un risultato da esso.
map = ImmutableSortedMap.copyOf(myOriginalMap, valueComparator);
Ora molto probabilmente funzionerà, ma:
- deve essere eseguito con una mappa completa completa
- Non provare i comparatori sopra su a
TreeMap
; non ha senso cercare di confrontare una chiave inserita quando non ha un valore fino a dopo l'inserimento, ovvero si romperà molto velocemente
Il punto 1 è un po 'una rottura per me; google collections è incredibilmente pigra (il che è buono: puoi fare praticamente ogni operazione in un istante; il vero lavoro viene fatto quando inizi a utilizzare il risultato) e questo richiede la copia di un'intera mappa!
Risposta "completa" / Mappa ordinata dal vivo per valori
Non preoccuparti però; se eri abbastanza ossessionato dall'avere una mappa "live" ordinata in questo modo, potresti risolvere non uno ma entrambi (!) dei problemi sopra con qualcosa di folle come il seguente:
Nota: questo è cambiato in modo significativo a giugno 2012 - il codice precedente non potrebbe mai funzionare: è necessaria una HashMap interna per cercare i valori senza creare un ciclo infinito tra TreeMap.get()
-> compare()
e compare()
->get()
import static org.junit.Assert.assertEquals;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import com.google.common.base.Functions;
import com.google.common.collect.Ordering;
class ValueComparableMap<K extends Comparable<K>,V> extends TreeMap<K,V> {
//A map for doing lookups on the keys for comparison so we don't get infinite loops
private final Map<K, V> valueMap;
ValueComparableMap(final Ordering<? super V> partialValueOrdering) {
this(partialValueOrdering, new HashMap<K,V>());
}
private ValueComparableMap(Ordering<? super V> partialValueOrdering,
HashMap<K, V> valueMap) {
super(partialValueOrdering //Apply the value ordering
.onResultOf(Functions.forMap(valueMap)) //On the result of getting the value for the key from the map
.compound(Ordering.natural())); //as well as ensuring that the keys don't get clobbered
this.valueMap = valueMap;
}
public V put(K k, V v) {
if (valueMap.containsKey(k)){
//remove the key in the sorted set before adding the key again
remove(k);
}
valueMap.put(k,v); //To get "real" unsorted values for the comparator
return super.put(k, v); //Put it in value order
}
public static void main(String[] args){
TreeMap<String, Integer> map = new ValueComparableMap<String, Integer>(Ordering.natural());
map.put("a", 5);
map.put("b", 1);
map.put("c", 3);
assertEquals("b",map.firstKey());
assertEquals("a",map.lastKey());
map.put("d",0);
assertEquals("d",map.firstKey());
//ensure it's still a map (by overwriting a key, but with a new value)
map.put("d", 2);
assertEquals("b", map.firstKey());
//Ensure multiple values do not clobber keys
map.put("e", 2);
assertEquals(5, map.size());
assertEquals(2, (int) map.get("e"));
assertEquals(2, (int) map.get("d"));
}
}
Quando lo inseriamo, ci assicuriamo che la mappa hash abbia il valore per il comparatore, quindi lo inseriamo nel TreeSet per l'ordinamento. Ma prima controlliamo la mappa hash per vedere che la chiave non è in realtà un duplicato. Inoltre, il comparatore che creiamo includerà anche la chiave in modo che i valori duplicati non cancellino le chiavi non duplicate (a causa del confronto ==). Questi 2 elementi sono fondamentali per garantire il mantenimento del contratto della mappa; se pensi di non volerlo, allora sei quasi sul punto di invertire completamente la mappa (a Map<V,K>
).
Il costruttore dovrebbe essere chiamato come
new ValueComparableMap(Ordering.natural());
//or
new ValueComparableMap(Ordering.from(comparator));
List<Map.Entry<...>> list =new LinkedList(map.entrySet())
eCollections.sort ....
così.