2015-04-23 2 views
6

molto simile a come un ImmutableList potrebbe essere esteso in quanto tale:Estensione di un ImmutableMap con valori aggiuntivi o nuove

ImmutableList<Long> originalList = ImmutableList.of(1, 2, 3); 
ImmutableList<Long> extendedList = Iterables.concat(originalList, ImmutableList.of(4, 5)); 

Se ho una mappa esistente, come potrei estendere (o creare una nuova copia con i valori sostituiti)?

ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7); 
ImmutableMap<String, Long> newPrices = … // Increase apple prices, leave others. 
             // => { "banana": 4, "apple": 9 } 

(. Non dobbiamo cercare una soluzione efficiente, come apparentemente that doesn't exist by design Questa domanda piuttosto cerca la soluzione più idiomatica.)

risposta

11

È possibile creare in modo esplicito un costruttore:

ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7); 
ImmutableMap<String, Long> newPrices = 
    new ImmutableMap.Builder() 
    .putAll(oldPrices) 
    .put("orange", 9) 
    .build(); 

EDIT:
Come indicato nei commenti, ciò non consentirà di ignorare i valori esistenti. Questo può essere fatto passando attraverso un blocco di inizializzazione di un diverso Map (ad esempio, HashMap). E 'tutt'altro che elegante, ma dovrebbe funzionare:

ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7); 
ImmutableMap<String, Long> newPrices = 
    new ImmutableMap.Builder() 
    .putAll(new HashMap<>() {{ 
     putAll(oldPrices); 
     put("orange", 9); // new value 
     put("apple", 12); // override an old value 
    }}) 
    .build(); 
+0

La restrizione è che i duplicati non sono ammessi - - Non mi permette di aumentare il prezzo delle mele. –

+0

@AndresJaanTack vedere la mia risposta modificata. Lontano da elegante, ma dovrebbe fare il trucco. – Mureinik

+4

Si consiglia di non consigliare "inizializzazione doppia parentesi". Vedi http://stackoverflow.com/a/9108655/95725 e http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/ – NamshubWriter

2

Basta copiare il ImmutableMap in una nuova HashMap, aggiungere gli elementi, e convertire in una nuova ImmutableMap

ImmutableMap<String, Long> oldPrices = ImmutableMap.of("banana", 4, "apple", 7); 
Map<String, Long> copy = new HashMap<>(oldPrices); 
copy.put("orange", 9); // add a new entry 
copy.put("apple", 12); // replace the value of an existing entry 

ImmutableMap<String, Long> newPrices = ImmutableMap.copyOf(copy); 
0

Beh, io ho fatto questo con flussi ma non è perfetto:

public static <K,V> Map<K,V> update(final Map<K,V> map, final Map.Entry<K,V> replace) 
{ 
    return Stream.concat(
     Stream.of(replace), 
     map.entrySet().stream() 
      .filter(kv -> ! replace.getKey().equals(kv.getKey())) 
    .collect(Collectors.toMap(SimpleImmutableEntry::getKey, SimpleImmutableEntry::getValue)); 
} 

e questo inserisce o aggiorna solo una singola voce. Si noti che ImmutableMap & il collettore associato può essere lasciato cadere in (che è quello che ho effettivamente utilizzato)

0

Non un codice terribilmente performante, ma il seguito avrebbe funzionato

private <K, V> ImmutableMap.Builder<K, V> update(final ImmutableMap.Builder<K, V> builder, final List<ImmutablePair<K, V>> replace) { 
    Set<K> keys = replace.stream().map(entry -> entry.getKey()).collect(toSet()); 
    Map<K, V> map = new HashMap<>(); 
    builder.build().forEach((key, val) -> { 
     if (!keys.contains(key)) { 
      map.put(key, val); 
     } 
    }); 
    ImmutableMap.Builder<K, V> newBuilder = ImmutableMap.builder(); 
    newBuilder.putAll(map); 
    replace.stream().forEach(kvEntry -> newBuilder.put(kvEntry.getKey(), kvEntry.getValue())); 
    return newBuilder; 
} 
+0

Potresti spiegare cosa fa questo codice e come risolve il problema? – Hexaholic