Slå sammen to kart med Java 8

1. Introduksjon

I denne raske opplæringen, vi vil demonstrere hvordan du slår sammen to kart ved hjelp av Java 8-funksjonene.

For å være mer spesifikk, vil vi undersøke forskjellige sammenslåingsscenarier, inkludert kart med dupliserte oppføringer.

2. Initialisering

La oss som en start definere to Kart forekomster:

privat statisk kart map1 = ny HashMap (); privat statisk kart map2 = ny HashMap ();

De Ansatt klassen ser slik ut:

offentlig klasse Ansatt {privat Lang id; privat strengnavn; // constructor, getters, setters}

Deretter kan vi skyve noen data inn i Kart forekomster:

Ansatt ansatt1 = ny ansatt (1L, "Henry"); map1.put (ansatt1.getnavn (), ansatt1); Ansatt ansatt2 = ny ansatt (22L, "Annie"); map1.put (medarbeider2.getnavn (), ansatt2); Ansatt ansatt3 = ny ansatt (8L, "John"); map1.put (medarbeider3.getnavn (), ansatt3); Ansatt ansatt4 = ny ansatt (2L, "George"); map2.put (ansatt4.getnavn (), ansatt4); Ansatt ansatt5 = ny ansatt (3L, "Henry"); map2.put (ansatt5.getnavn (), ansatt5);

Merk at vi har identiske nøkler til ansatt1 og ansatt5 oppføringene i kartene våre som vi bruker senere.

3. Map.merge ()

Java 8 legger til en ny slå sammen() funksjon inn i java.util.Kart grensesnitt.

Her er hvordan slå sammen() funksjonen fungerer: Hvis den angitte nøkkelen ikke allerede er knyttet til en verdi eller verdien er null, knytter den nøkkelen til den gitte verdien.

Ellers erstatter den verdien med resultatene av den gitte omkartingsfunksjonen. Hvis resultatet av omkartingsfunksjonen er null, fjerner det resultatet.

La oss først konstruere en ny HashMap ved å kopiere alle oppføringene fra kart1:

Map map3 = nytt HashMap (map1);

Neste, la oss introdusere slå sammen() funksjon sammen med flettingsregel:

map3.merge (nøkkel, verdi, (v1, v2) -> ny ansatt (v1.getId (), v2.getName ())

Til slutt vil vi iterere over kart2 og slå sammen oppføringene i kart3:

map2.forEach ((nøkkel, verdi) -> map3.merge (nøkkel, verdi, (v1, v2) -> ny ansatt (v1.getId (), v2.getName ())));

La oss kjøre programmet og skrive ut innholdet på kart3:

John = Ansatt {id = 8, navn = "John"} Annie = Ansatt {id = 22, navn = "Annie"} George = Ansatt {id = 2, navn = "George"} Henry = Ansatt {id = 1, name = "Henry"}

Som et resultat, vår kombinert Kart har alle elementene fra den forrige HashMap innganger. Oppføringer med dupliserte nøkler er slått sammen til en oppføring.

Vi merker også at Ansatt objektet til den siste oppføringen har id fra kart1, og verdien plukkes fra kart2.

Dette er på grunn av regelen vi definerte i fusjonsfunksjonen vår:

(v1, v2) -> ny ansatt (v1.getId (), v2.getName ())

4. Stream.concat ()

De Strøm API i Java 8 kan også gi en enkel løsning på problemet vårt. Først, vi trenger å kombinere vår Kart forekomster til en Strøm. Det er akkurat det Stream.concat () operasjonen gjør:

Strøm kombinert = Stream.concat (map1.entrySet (). Stream (), map2.entrySet (). Stream ());

Her passerer vi kartoppføringssettene som parametere. Deretter må vi samle resultatet vårt til et nytt Kart. Til det kan vi bruke Collectors.toMap ():

Kartresultat = combined.collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue));

Som et resultat vil samleren bruke de eksisterende nøklene og verdiene på kartene våre. Men denne løsningen er langt fra perfekt. Så snart samleren vår møter oppføringer med dupliserte nøkler, kaster den en IllegalStateException.

For å håndtere dette problemet legger vi bare til en tredje "fusjon" lambda-parameter i samleren vår:

(verdi1, verdi2) -> ny ansatt (verdi2.getId (), verdi1.getnavn ())

Det vil bruke lambda-uttrykket hver gang en duplikatnøkkel oppdages.

Til slutt, sette alt sammen:

Kartresultat = Stream.concat (map1.entrySet (). Stream (), map2.entrySet (). Stream ()) .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (value1) , verdi2) -> ny ansatt (verdi2.getId (), verdi1.getnavn ())));

Til slutt, la oss kjøre koden og se resultatene:

George = Ansatt {id = 2, navn = "George"} John = Ansatt {id = 8, navn = "John"} Annie = Ansatt {id = 22, navn = "Annie"} Henry = Ansatt {id = 3, name = "Henry"}

Som vi ser, dupliserte oppføringer med nøkkelen “Henry” ble slått sammen til et nytt nøkkelverdipar der IDen til det nye Ansatt ble plukket fra kart2 og verdien fra kart1.

5. Stream.of ()

For å fortsette å bruke Strøm API, kan vi gjøre vårt Kart forekomster i en enhetlig strøm ved hjelp av Stream.of ().

Her trenger vi ikke lage en ekstra samling for å jobbe med strømmer:

Map map3 = Stream.of (map1, map2) .flatMap (map -> map.entrySet (). Stream ()) .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (v1 , v2) -> ny ansatt (v1.getId (), v2.getName ())));

Først, vi forvandler kart1 og kart2 inn i en enkelt strøm. Deretter konverterer vi strømmen til kartet. Som vi kan se, er det siste argumentet fra å kartlegge() er en sammenslåingsfunksjon. Det løser duplikatnøkkelproblemet ved å velge id-feltet fra v1 oppføring, og navnet fra v2.

Det trykte kart3 forekomst etter å ha kjørt programmet:

George = Ansatt {id = 2, navn = "George"} John = Ansatt {id = 8, navn = "John"} Annie = Ansatt {id = 22, navn = "Annie"} Henry = Ansatt {id = 1, name = "Henry"}

6. Enkel streaming

I tillegg kan vi bruke en strøm() rørledning for å sette sammen kartoppføringene våre. Kodebiten nedenfor viser hvordan du legger til oppføringene fra kart2 og kart1 ved å ignorere duplikatoppføringene:

Map map3 = map2.entrySet () .stream () .collect (Collectors.toMap (Map.Entry :: getKey, Map.Entry :: getValue, (v1, v2) -> new Employee (v1.getId (), v2 .getName ()), () -> ny HashMap (map1)));

Som vi forventer er resultatene etter sammenslåingen:

{John = Ansatt {id = 8, navn = "John"}, Annie = Ansatt {id = 22, navn = "Annie"}, George = Ansatt {id = 2, navn = "George"}, Henry = Ansatt { id = 1, name = "Henry"}}

7. StreamEx

I tillegg til løsninger som tilbys av JDK, kan vi også bruke det populære StreamEx bibliotek.

For å si det enkelt, StreamEx er en forbedring for Strøm API og gir mange flere nyttige metoder. Vi bruker en EntryStream forekomst for å operere på nøkkelverdipar:

Map map3 = EntryStream.of (map1) .append (EntryStream.of (map2)) .toMap ((e1, e2) -> e1);

Tanken er å slå strømmen av kartene våre sammen til en. Så samler vi oppføringene i det nye kart3 forekomst. Viktig å nevne, den (e1, e2) -> e1 uttrykk da det hjelper til med å definere regelen for håndtering av duplikatnøklene. Uten den vil koden vår kaste en IllegalStateException.

Og nå, resultatene:

{George = Ansatt {id = 2, navn = "George"}, John = Ansatt {id = 8, navn = "John"}, Annie = Ansatt {id = 22, navn = "Annie"}, Henry = Ansatt { id = 1, name = "Henry"}}

8. Oppsummering

I denne korte artikkelen lærte vi forskjellige måter å slå sammen kart på Java 8. Mer spesifikt, vi brukte Map.merge (), Stream API, StreamEx bibliotek.

Som alltid kan koden som ble brukt under diskusjonen finnes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found