2016-03-01 23 views
5
Map<String, String> map1 = new HashMap<>(); 
map1.put("k1", "v1"); 
map1.put("k2", "v2"); 
map1.put("k3", "v3"); 

Map<String, String> map2 = new HashMap<>(); 
map2.put("v1", "val1"); 
map2.put("v2", "val2"); 
map2.put("v3", "vav3"); 

Chcę zaktualizować wartości map1 tak, że ma dane:wartości aktualizowaniu mapy na podstawie innych mapie w Javie

  • „K1”, „val1”
  • "K2", "wart2"
  • "K3", "val3"

Moje rozwiązanie:

for (Map.Entry<String, String> entry : map1.entrySet()) { 
    map1.put(entry.getKey(), map2.get(entry.getValue())); 
} 

Czy istnieje lepszy sposób to zrobić?

Edit: używam Java 7, ale ciekaw, czy istnieje lepszy sposób w Javie 8.

+0

Niezupełnie, nie - chociaż wygląda na to, że powinieneś robić 'map3.put' zamiast' map1.put'? –

+1

to jest java 8? w takim przypadku strumienie mogą ci pomóc. – njzk2

+0

Powinieneś też robić 'map2.put' zamiast' map1.put' przy wypełnianiu 'map2.'. – Atri

Odpowiedz

3

Począwszy Java 8, można po prostu mieć

map1.replaceAll((k, v) -> map2.get(v)); 

replaceAll(function) zastąpi wszystkie wartości z mapy map1 z wynikiem zastosowania danej funkcji. W takim przypadku funkcja po prostu pobiera wartość z map2.

Należy zauważyć, że to rozwiązanie ma takie same problemy, jak początkowy kod: jeśli map2 nie ma odpowiadającego odwzorowania, zostanie zwrócone null. Możesz wtedy zadzwonić pod numer getOrDefault, aby mieć domyślną wartość.

public static void main(String[] args) { 
    Map<String, String> map1 = new HashMap<>(); 
    map1.put("k1", "v1"); 
    map1.put("k2", "v2"); 
    map1.put("k3", "v3"); 

    Map<String, String> map2 = new HashMap<>(); 
    map2.put("v1", "val1"); 
    map2.put("v2", "val2"); 
    map2.put("v3", "val3"); 

    map1.replaceAll((k, v) -> map2.get(v)); 

    System.out.println(map1); // prints "{k1=val1, k2=val2, k3=val3}" 
} 
+0

Dowolny komentarz do Java 7? –

+0

@dev ツ Szczerze, pomijając przypadek, o którym wspomniałem (mapa nie ma odpowiedniego klucza), nie ma miejsca na poprawę. W porządku, tak jak jest. – Tunaki

0

w Java 8 można napisać:

map1.entrySet() 
    .stream() 
    .map(entry -> new SimpleEntry(entry.getKey(), map2.get(entry.getValue()))) 
    .collect(Collectors.toMap(entry -> entry.getKey(), entry.getValue())); 

Nie najmilsza rzecz, chociaż, ale nadal bez mutacji rozwiązanie.

+0

lepszy sposób w Java7? –

1

W przypadku Java 7 nic więcej nie można zrobić, robisz to już w najlepszy możliwy sposób.

Dodaję tę odpowiedź jako odniesienie, aby pokazać, że w takim przypadku użycie wyrażeń Lambda w Javie 8 będzie jeszcze gorsze. Zobacz ten przykład:

public static void main(String[] args) { 
    Map<String, String> map1 = new HashMap<>(); 
    final Map<String, String> map2 = new HashMap<>(); 

    for (int i=0; i<100000; i++){ 
     map1.put("k"+i, "v"+i); 
     map2.put("v"+i, "val"+i); 
    } 

    long time; 
    long prev_time = System.currentTimeMillis(); 
    for (Map.Entry<String, String> entry : map1.entrySet()) { 
     map1.put(entry.getKey(), map2.get(entry.getValue())); 
    } 
    time = System.currentTimeMillis() - prev_time; 
    System.out.println("Time after for loop " + time); 


    map1 = new HashMap<>(); 
    for (int i=0; i<100000; i++){ 
     map1.put("k"+i, "v"+i); 
    } 

    prev_time = System.currentTimeMillis(); 
    map1.replaceAll((k, v) -> map2.get(v)); 
    time = System.currentTimeMillis() - prev_time; 
    System.out.println("Time after for loop " + time); 
} 

Wyjście do tego będą:

Time after for loop 40 
Time after for loop 100 

Druga pętla jest zmienna, ale zawsze większy od pierwszego.

Nie jestem specjalistą Lambda, ale myślę, że są bardziej być przetwarzane z nim niż zwykły „foreach” w pierwszym scenariuszu

uruchomiony ten przypadek testowy kółko was dostanie za lambda prawie zawsze dwa razy więcej niż pierwszy przypadek "foreach".