Megjegyzés: a lenyitható megoldások füleknél rosszul van a kód tördelve, mert csak így engedi a HTML, de te használd az automatikus formázást IntelliJ-ben!
A Map adatstruktúra kulcs-érték párokat jelent.
Például: Az osztályban kinek mi a kedvenc színe?
| Kulcs | Érték |
|---|---|
| M. Béla | bugyirózsaszín |
| I. Lili | libafoszöld |
| Z. Margit | diplomatakék |
| U. Pityu | bugyirózsaszín |
Kulcs: az osztálytárs neve, ami egyértelműen beazonosítja a tanulót, tehát két ugyanolyan kulcs nem szerepelhet (nem lehet két Z. Margit)
Érték: az osztálytárs kedvenc színe, ami mindig a kulcshoz tartozó érték, szerepelhetnek ugyanolyan értékek (tehát több tanulónak is lehet ugyanaz a kedvenc színe)
Ezek a kulcsok és értékek bármilyen összetett típusok lehetnek, (tehár primitív típusok nem), a jelen esetben a kulcs az String (hiszen szöveges érték) és az érték is String, (hiszen az is szöveges érték.)
Map-ek deklarálásakor nekünk explicit meg kell adnunk milyen típusúak lesznek a kulcsaink és értékeink, tehát a kacsacsőrbe két típust is be kell írnünk - az eddig tanult kollekciókkal (List, Set) szemben, ahol csak egy típust kell megadnunk.
Map<String, String> tanuloKedvencSzine;
A kacsacsőrben az első típus a kulcs típusa, a második az értéké.
Vegyünk egy olyan példát, ahol eltérő a kulcs és az érték típusa! Ilyen az osztály tanulóinak az átlaga:
| Kulcs | Érték |
|---|---|
| M. Béla | 2.1 |
| I. Lili | 4.9 |
| Z. Margit | 1.0 |
| U. Pityu | 3.8 |
Ezt a kulcs-érték párokat tartalmazó "táblázatot" az alábbi adatstruktúrában tudnánk reprezentálni:
Map<String, Double> tanuloAtlaga;
Az érték egy tört szám, ezért Double-ben tároljuk.
Kérdés: miért nem kisbetűs double-ben?
Válasz
Mert primitív típusokat nem tárolhatunk Map-ben!
Hogyan nézne ki, ha a tanulóknak nem csak az átlagát, de minden jegyét el szeretném tárolni?
| Kulcs | Érték |
|---|---|
| M. Béla | 1, 3, 3, 4, 3, 2 |
| I. Lili | 5, 5, 5, 5, 5, 4, 5, 5 |
| Z. Margit | 1, 1, 1 |
| U. Pityu | 4, 5, 3, 5 |
A táblázatban látjuk hogy most mintha "több érték" szerepelne az érték osztályban - méghozzá nem is mindig ugyanannyi darab!
Fontos megjegyezni, hogy a Map kulcs-érték párokat jelent, nem pedig kulcs-értékek párokat, tehát
ez nem valami ilyemi adatsruktúra lesz:
Map<String, Integer, Integer, Integer, Integer, Integer, ..., ?> tanuloJegyei;
Hogyan lehetne akkor mégis megoldani ezt?
A kulcsom a tanuló neve, az értékem pedig...? A tanuló jegye...-inek a LISTÁJA!
Azaz ez így fog kinézni: Map<String, List<Integer>> tanuloJegyei;
Figyeld meg a kacsacsőröket, melyik "mettől meddig tart"!
Kulcs: String
Érték: List<Integer>
Tehát minden Stringhez tartozik egy Integer lista!
Megjegyzés: kulcsként is tudunk kollekciókat (Set, List, akár Map) megadni, de nem szokás!
A Map egy interfész, egyik implementációja a HashMap, mi mindig ezt az implementációt
fogjuk használni: Map<String, List<Integer>> tanuloJegyei = new HashMap<>();
A Map nem egy rendezett adatstruktúra, kulcs alapján való keresésben teljesít jól. Használni akkor érdemes, amikor egy kulcsra fogsz rákeresni és annak kell lekérned a hozzátartozó adatait!
Gondolkozz el, milyen adatstrukturában (List, Set, Map) és milyen típusokkal tárolnád el az alábbi adatokat!
Van egy kártyapaklid, aminek mindig meg kell keverned a lapjait!
Megoldás
Listában: List < Card > cards;
Van egy telefonkönyved, ahol név alapján szeretnél keresni, és eltárolni infókat, pl. telefonszám, foglalkozás.
Megoldás
Mapben: Map < String, ContactInfo > phoneBook; Ahol a ContactInfo osztály (amit te magad hozol létre) tartalmazza a telefonszámot és a foglalkozást is!
Egy magyar-angol szótárat szerenél készíteni.
Megoldás
Mapben: Map < String, String > dictionary;
Készítsd egy map-et, ami a barátaidnak a régi óvodai jeleit tárolja el!
Megoldás
Map< String, String> ovodaiJelek = new HashMap<>();
Töltsd fel a saját neveddel és jeleddel!
Ehhez használd a .put() metódust!
Megoldás
ovodaiJelek.put("Zámbó Jimmy", "korona");
Adj még hozzá legalább 2 kulcs-érték párt! Ezeket a párokat Entry-nek hívjuk.
Vegyél fel egy olyan entry-t is, ahol a kulcs különböző, ám az érték már szerepel az értékek közt!
Vegyél fel egy olyan entry-t, ahol már szereplő kulcsot adsz meg! Mi történik ilyenkor? Az eredeti érték marad vagy felülíródik vagy összefűzödik?
Írasd ki a maped-et! System.out.println(ovodaiJelek);
Milyen sorrenben írja ki az elemeket?
Távoltísd el a kulcs alapján
az egyik kulcs-érték párt a remove() metódussal!
Megoldás
`ovodaiJelek.remove("Zámbó Jimmy");`
Kérd le a .get() metódussal az egyik kulcshoz tartozó
értéket és írasd ki!
Megoldás
System.out.println(ovodaiJelek.get("Zámbó Jimmy")); // korona
Írd ki az összes kulcsot a .keySet()-tel!
Megoldás
System.out.println(ovodaiJelek.keySet());
Tedd meg ugyanezt az értékekre, keresd meg, melyik metódus használható erre!
Megoldás
System.out.println(ovodaiJelek.values());
Nézd meg az .entrySet() metódust, mivel tér vissza? (Hívd meg a mapeden és vidd rá a kurzort, olvasd el a fejlécét és a leírását!)
Megoldás
Mily' meglepő, Set-tel tér vissza, amiben a kulcs-érték párokból képzett Entry-ket tároljuk
Vizsgáld meg mi a különbség aközött,
ha csak a maped írod ki,
és ha a map entrySet()-jét!
Megoldás
Kiíráskor nagyon minimális különbséget látunk, a kapcsoszárójel helyett szögletes a zárójel, ám itt a háttérben az történik, hogy más az adatstruktúra, amit kiíratunk: első esetben Map, második esetben Set!
Mi történik, ha nem létező kulcsot adsz meg paraméterül
a .get() metódusnak?
Megoldás
null-t ad vissza
Hogyan oldanád meg, hogy kicseréld a saját óvodai jeledet egy másikra?
Írj egy mapet, ami testmagasságaokat tart számon! Add hozzá az alábbi értékeket:
heightMap.put("Sziproka", 131);
heightMap.put("Csuporka", 134);
heightMap.put("Puszedli", 123);
heightMap.put("X-Professzor", 185);
heightMap.put("Mohó Jojó", 152);
Írasd ki az összes testmagasságot! (A neveket NE!)
Írd ki, mekkora a legnagyobb testmagasság!
Segítség
A values()-on kell végigiterálni, érdemes foreach ciklust használnod!
Még több segítség
A foreach ciklus fejléce: for (int height : heightMap.values())
A segédváltozódnak semmiképp se adj meg alapértéknek
0-t, de azt se csináld, hogy lekéred egy konkrét kulcs
értékét és azt állítod be neki!
Ehelyett használd ezt:
int maxHeight = Integer.MIN_VALUE;
Írd ki, ki a legmagasabb! Ez már sokkal csúnyább megoldás lesz :)
Segítség
Ugyanúgy meg kell keresned a legnagyobb magasságot, majd eltárolnod a hozzá tartozó kulcsot! Ez hasonló ahhoz, mint amikor a tömbön való végigiteráláskor eltároluk az indexet és az indexen lévő értéket is! Azaz vegyél fel egy segédváltozót a névnek!
Mi lesz most a kollekció, amin végig kell iterálnod, hogy fog kinézni a foreach ciklus?
Segítség
Az .entrySet()-en kell végigmenni!
TRÜKK! Írd be IntelliJ-be, hogy heightMap.entrySet(),
majd nyomj egy Alt+Entert! Válaszd azt az opciót, hogy
Iterate over... és voilá! Automatikusan kitöltötte
neked a foreach fejlécét! Igen, csúnya!:)
Érdemes átírni az automatikusan generált "aktuális elem"
változójának a nevét stringIntegerEntry-ről akár csak sima
entry-re! Ezen a Map.Entry típusú változón fogsz tudni
hívni .getKey() és .getValue() metódusokat!
Segítség
for (Map.Entry< String, Integer> entry : heightMap.entrySet()) {
// TODO
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}
Írd ki, ki a legalacsonyabb és mennyi a magassága!
Sziporka kiállt az esőbe és nőtt 1 centit:
növeld meg a magasságát 1-gyel!
(Ne a put()-ot írd át!)
Nem kell túlbonyolítani, 1-2 sor összesen!
Megoldás egy sorban
heightMap.put("Sziporka", heightMap.get("Sziporka") + 1);
// Ha nem tudtad magadtól megoldani, írd át ezt a megoldást 2 sorba!
// Készíts egy int newHeight változót...!
Készítsünk el egy jegyeket eltároló mapet grades néven,
ami minden tanulóhoz
hozzátársít egy listát, amiben a jegyei szerepelnek!
Így tudod feltölteni elemekkel:
List<Integer> aliceGrades = new ArrayList<>();
aliceGrades.add(5);
aliceGrades.add(2);
aliceGrades.add(1);
grades.put("Alice", aliceGrades);
List<Integer> bobGrades = new ArrayList<>();
bobGrades.add(4);
bobGrades.add(3);
grades.put("Bob", bobGrades);
VAGY sokkal tömörebben:
grades.put("Alice", Arrays.asList(5, 2, 1));
grades.put("Bob", Arrays.asList(4, 3));
Vegyél fel jegyeket egy harmadik, Charlie nevű diáknak is!
TO BE CONTINUED...
Készíts egy olyan mapet, ami egy névhez társít egy darab jegyet, ez a jegy lesz a tanuló félév végi jegye matekból. Készítsd még ilyen mapeket töriből, irodalomból és kémiából.
Ezen mapek alapján fűzz össze egy olyan mapet, ami tartalmazza a tanuló minden egyes tantárgyból kapott félév végi jegyét! Tehát ha Julika 1-est kapott matekból, 3-ast kémiából és matekból és 4-est irodalomból, akkor hozzá ez a négy szám (1, 3, 3, 4) tartozzon az új mapben! (A sorrend nem számít!)