2013-04-19 4 views
17

A un certo punto del mio codice, ho creato un Set<Map.Entry<K, V>> da una mappa. Ora voglio ricreare la stessa forma della mappa, quindi voglio convertire lo HashSet<Map.Entry<K, V>> in uno HashMap<K, V>. Java ha una chiamata nativa per farlo, o devo scorrere gli elementi del set e costruire manualmente la mappa?Converti Set <Map.Entry <K, V>> a HashMap <K, V>

+0

Come hai creato 'set' da' Map', usando la logica chiave o un valore o personalizzato? inoltre non esiste un metodo 'nativo' per' HashSet' su 'HashMap'. È necessario iterare e utilizzare una logica mentre si inserisce in 'HashMap' come si sceglie la chiave e il valore. – harsh

+0

@Paul grazie ora la domanda è chiara. – harsh

+1

Non penso che Map.Entry debba essere usato in questo modo. L'implementazione utilizzata da 'HashMap' sovrascrive' hashCode' e 'equals' per esempio? –

risposta

17

Non vi è alcuna API incorporata in java per la conversione diretta tra HashSet e HashMap, è necessario scorrere il set e utilizzare Entry compilare la mappa.

un approccio:

Map<Integer, String> map = new HashMap<Integer, String>(); 
    //fill in map 
    Set<Entry<Integer, String>> set = map.entrySet(); 

    Map<Integer, String> mapFromSet = new HashMap<Integer, String>(); 
    for(Entry<Integer, String> entry : set) 
    { 
     mapFromSet.put(entry.getKey(), entry.getValue()); 
    } 

Anche se quello che è lo scopo qui, se fate eventuali cambiamenti Set che rifletteranno anche nel Map come set restituito da Map.entrySet è backup Map. Vedere javadoc di seguito:

Impostare < Entry < Integer, String >> java.util.Map.entrySet()

Restituisce una vista Set delle mappature contenute in questa mappa. Il set è supportato dalla mappa, quindi le modifiche alla mappa si riflettono nel set e viceversa. Se la mappa viene modificata mentre un'iterazione sul set è in corso (tranne tramite l'operazione di rimozione dell'iteratore o tramite l'operazione setValue su una voce della mappa restituita dall'iteratore ) i risultati dell'iterazione non sono definiti. Il set supporta la rimozione degli elementi , che rimuove la mappatura corrispondente dalla mappa, tramite le operazioni Iterator.remove, Set.remove, removeAll, retainAll e clear . Non supporta le operazioni add o addAll.

1

Soluzione Java 8 discretamente breve. Può far fronte a chiavi duplicate.

Map<Integer, String> map = new HashMap<>(); 
    //fill in map 
    Set<Map.Entry<Integer, String>> set = map.entrySet(); 
    Map<Integer, String> mapFromSet = set.stream().collect(Collectors.toMap(Entry::getKey, 
     Entry::getValue, 
     (a,b)->b)); 

Edit: grazie a shmosel che merita più credito di me per questo

+0

No. Il tuo BiConsumer non combina le mappe. – Joe

+0

Nel codice precedente, il metodo di accettazione di BiConsumer non viene mai chiamato. Avrei preferito utilizzare null, ma il metodo di raccolta genera stupidamente un NPE in quel caso. – mikeyreilly

+1

@mikeyreilly, [la documentazione] (https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#collect-java.util.function.Supplier-java.util .function.BiConsumer-java.util.function.BiConsumer-) non dice esplicitamente che il combinatore non viene mai chiamato per il flusso sequenziale. Quindi violi semplicemente il contratto del metodo. –

0

In Java 8 con corretta combinatore

Map<Integer, String> map = new HashMap<>(); 
//fill in map 
Set<Map.Entry<Integer, String>> set = map.entrySet(); 

Map<Integer, String> mapFromSet =set.stream().collect(HashMap::new,(t, u) -> t.put(u.getKey(), u.getValue()), 
(Map mapToReturn, Map otherMap) -> 
    { 
     otherMap.entrySet().forEach((Map.Entry entry) -> { 
      mapToReturn.put(entry.getKey(),entry.getValue()); 
     }); 
     return mapToReturn;});); 
26

Java-8 soluzione più semplice che coinvolge Collectors.toMap:

Map<Integer, String> mapFromSet = set.stream() 
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue)); 

Viene generato un IllegalStateException se d si trova la chiave uplicate.

+0

Cosa sono gli NPE se qualche valore è nullo? –

0

Come di Java 9, abbiamo Map.ofEntries. Prendono solo le voci come array, quindi è necessario convertirle prima con toArray() e buttare fuori le informazioni sul tipo.

@SuppressWarnings("unchecked") 
(Map.Entry<K, V>[] array = entrySet.toArray((Map.Entry<K, V>[])new Map.Entry<?, ?>[entrySet.size()]); 
Map<K, V> map = Map.ofEntries(array); 

I comuni Apache hanno metodi simili.di ArrayUtils.toMap Commons Lang:

Map<Object, Object> map = ArrayUtils.toMap(entrySet.toArray()); 

// to recover the type... 
@SuppressWarnings("unchecked") 
Map<K, V> typedMap = (Map<K, V>)(Map<?, ?>)map; 

Commons Collezioni MapUtils.putAll:

Map<K, V> map = MapUtils.putAll(new HashMap<K, V>(), entrySet.toArray());