Gyakorlati alapok III.
Leképezés (Map)
Ismételjük meg az egyik
előző fejezet legfontosabb megállapításait:
A Map legfőbb jellegzetessége, hogy kulcs-érték párokat tartalmaz. 1 kulcs (key) csak 1 értéket (value) azonosíthat be, illetve tiltott a többszörös kulcshasználat (ellenben megengedett a többszörös értékhasználat, természetesen több kulcs esetén).
Valós életből vett példák: személyi szám és személynév adatbázisa, ahol kikötés, hogy 1 személyhez csak 1 személyi szám tartozhat (és fordítva).
További érdekes Map-példa: ruhatári szituáció, amelyben értékként kezelt ruháinkat a ruhatárnak nevezett tárolóegységbe (kell) tennünk. Az érték azonosítása nem név, hanem egy egyedi kulcs alapján történik (számozott jegy, biléta). Tiltott a többszörös kulcshasználat (ha adott számú biléta többször is előfordul), ám ebben a ruhatári helyzetben 1 kulcshoz rendelhetünk több értéket is (1 biléta, több kabát).
Két Map-objektum akkor egyenlő, ha a kulcs-érték párjaik megegyeznek.
A sorrend nem számít.
A Map működése alapvetően hasonló a többi, már ismertetett Collection-leszármazotthoz (Set és List), a különbségek főként a kulcs-érték (key-value) páros egyedi jellegzetességeiből és működéséből keletkeznek. A konkrét Java-kódok előtt ellenőrizzük le a Map interfész-implementációját, amelyben észrevehetünk új, specifikus függvényeket:
public interface Map {
V put(K key, V value);
V get(Object key);
V remove(Object key);
boolean containsKey(Object key);
boolean containsValue(Object value);
int size();
boolean isEmpty();
void putAll(Map<? extends K,? extends V> t);
void clear();
public Set<K> keySet();
public Collection<V> values();
public Set<Map.Entry<K,V>> entrySet();
public interface Entry {
K getKey();
V getValue();
V setValue(V value);
}
}
Ezután pedig nézzünk meg néhány futtatható Java-kódon keresztül további, Map-ra jellemző tulajdonságot!
Egy Map-objektum létrehozása a megszokottak szerint a következőféleképpen történik:
Map<String, Integer> map = new HashMap<>();
Kezdeti Map-típusunk tehát a HashMap, amely egyszerű és könnyen kezelhető objektumot ad vissza. Látható, hogy 1 lépésben kell gondoskodnunk a kulcs-értékpár típusainak beállításáról is (itt String és Integer). Az objektum létrehozása után lehetőségünk van azt kulccsal és értékkel feltölteni a put() metódus segítségével:
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Zoltan", 1);
map.put("Arpad", 2);
map.put("Bela", 3);
System.out.println(map);
}
}
Végeredmény:
{Bela=3, Zoltan=1, Arpad=2}
A rendszer bár engedi a duplikált vagy többszörös kulcs-értékpár tartalmat, de ezen, azonos elemekre külön-külön hivatkozni nem lehet. Rákereséskor az első előfordulás fog előbukkanni:
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Zoltan", 1);
map.put("Arpad", 2);
map.put("Bela", 3);
map.put("Zoltan", 1);
map.put("Arpad", 2);
map.put("Bela", 3);
System.out.println(map);
}
}
Végeredmény:
{Bela=3,
Zoltan=1, Arpad=2}
Mivel a kereső függvények többsége boolean típusú, a Map esetében szintén true vagy false kimeneti értékkel jelzik, hogy az objektum tartalmazza-e a kulcsot vagy az értéket. Ezt könnyen le tudjuk ellenőrizni a containsKey() és containsValue() függvények segítségével:
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Zoltan", 1);
map.put("Arpad", 2);
map.put("Bela", 3);
map.put("Zoltan", 1);
map.put("Arpad", 2);
map.put("Bela", 3);
System.out.println(map);
System.out.println(map.containsKey("Zoltan"));
System.out.println(map.containsValue(1));
}
}
Végeredmény:
{Bela=3,
Zoltan=1, Arpad=2}
true
true
Most nézzünk meg néhány további függvényt 1 működő Java-kódon belül:
-
isEmpty() - üres-e az objektum,
-
size() - az objektum mérete (elemszáma),
-
remove() - elemeltávolítás,
-
replace() - elemcsere,
-
clear() - az objektum összes elemének cseréje.
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Zoltan", 1);
map.put("Arpad", 2);
map.put("Bela", 3);
map.put("Zsolt", 4);
map.put("Laszlo", 5);
map.put("Viktor", 6);
System.out.println(map);
System.out.println("Az objektum üres? " + map.isEmpty());
System.out.println("Az objektum mérete: " + map.size());
map.remove("Viktor", 6);
System.out.println("Az objektum 'Viktor-6' eltávolítása után:
" + map);
map.replace("Zoltan", 2);
System.out.println("Az objektum 'Zoltan-1' értékének
átállítása után: " + map);
map.clear();
System.out.println("Az objektum törlés után: " + map);
}
}
Végeredmény:
{Laszlo=5,
Zsolt=4, Viktor=6, Bela=3, Zoltan=1, Arpad=2}
Az objektum üres? false
Az objektum mérete: 6
Az objektum 'Viktor-6' eltávolítása után: {Laszlo=5, Zsolt=4, Bela=3, Zoltan=1,
Arpad=2}
Az objektum 'Zoltan-1' értékének átállítása után: {Laszlo=5, Zsolt=4, Bela=3,
Zoltan=2, Arpad=2}
Az objektum törlés után: {}
Érdemes külön kiemelnünk még 2 további függvényt, amelyek egyszerűen kilistázzák a kulcs-, és és értékhalmazokat (keySet() és values()):
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("Zoltan", 1);
map.put("Kriszta", 2);
map.put("Szilvia", 3);
map.put("Hanna", 4);
map.put("Arpad", 5);
map.put("Bela", 6);
map.put("Peter", 7);
System.out.println(map.keySet());
System.out.println(map.values());
}
}
Végeredmény:
[Bela,
Zoltan, Szilvia, Arpad, Peter, Hanna, Kriszta]
[6, 1, 3, 5, 7, 4, 2]
Most pedig ellenőrizzük le 2 Map-objektum egyenlőségét a már említett állítás alapján:
Két Map-objektum akkor egyenlő, ha a kulcs-érték párjaik megegyeznek.
A sorrend nem számít.
A létrehozott 2 Map-objektumot ugyanolyan kulcs-értékpárokkal, de különböző beviteli sorrendben töltjük fel:
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>();
map1.put("Zoltan", 1);
map1.put("Arpad", 2);
map1.put("Bela", 3);
map2.put("Arpad", 2);
map2.put("Zoltan", 1);
map2.put("Bela", 3);
if(map1.equals(map2)) {
System.out.println("A 2 objektum
egyenlő.");
}
else
System.out.println("A 2 objektum nem
egyenlő.");
}
}
Végeredmény:
A 2
objektum egyenlő.
Bármelyik elemet is megváltoztatjuk, a 2 objektum már nem lesz egyenlő:
import java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>();
map1.put("Zoltan", 1);
map1.put("Arpad", 2);
map1.put("Bela", 3);
map2.put("Arpad", 2);
map2.put("Zoltan", 1);
map2.put("Bela", 4);
if(map1.equals(map2)) {
System.out.println("A 2 objektum
egyenlő.");
}
else
System.out.println("A 2 objektum nem
egyenlő.");
}
}
Végeredmény:
A 2
objektum nem egyenlő.
Ha már 2 db Map-objektum elénk ugrott, ellenőrizzünk le az egyik tömeges műveletet is (bulk operations). Az alábbi Java-kódban 2 db Map-objektum unióját állítjuk elő egy 3. objektumban:
import
java.util.*;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map1 = new HashMap<>();
Map<String, Integer> map2 = new HashMap<>();
Map<String, Integer> mapEredmeny = new HashMap<>();
map1.put("Zoltan", 1);
map1.put("Kriszta", 1);
map1.put("Szilvia", 2);
map1.put("Hanna", 3);
map2.put("Zoltan", 1);
map2.put("Arpad", 2);
map2.put("Bela", 3);
map2.put("Peter", 4);
mapEredmeny = map1;
mapEredmeny.putAll(map2);
System.out.println(mapEredmeny);
}
}
Végeredmény:
{Bela=3,
Zoltan=1, Szilvia=2, Arpad=2, Peter=4, Hanna=3, Kriszta=1}
Figyeljük meg, hogy szándékosan használunk fel egy duplikált kulcs-értékpárt ("Zoltan", 1), ám az az eredményobjektumban nem duplikálva jelenik meg.
A Map természetesen másra is felhasználható. Az alábbi futtatható Java-kódban segítségével szógyakoriságot vizsgálunk:
import
java.util.*;
public class Main {
public static void main(String args[]) {
Map<String, Integer> map = new HashMap<String, Integer>();
String [] bemenetiTomb = {"to", "be", "or", "not", "to",
"be"};
for(int i = 0; i < bemenetiTomb.length; i++) {
Integer gyakorisag = map.get(bemenetiTomb[i]);
map.put(bemenetiTomb[i], (gyakorisag
== null ? 1 : gyakorisag + 1));
}
System.out.println(map.size() + " különböző szó:\n" + map);
}
}
Végeredmény:
4
különböző szó:
{not=1, be=2, or=1, to=2}
Látható, hogy a HashMap nem biztosít rendezettséget. A kulcsok betűrendbe állítását a TreeMap képes nekünk elvégezni:
import
java.util.*;
public class Main {
public static void main(String args[]) {
Map<String, Integer> map = new TreeMap<String, Integer>();
String [] bemenetiTomb = {"to", "be", "or", "not", "to",
"be"};
for(int i = 0; i < bemenetiTomb.length; i++) {
Integer gyakorisag = map.get(bemenetiTomb[i]);
map.put(bemenetiTomb[i], (gyakorisag
== null ? 1 : gyakorisag + 1));
}
System.out.println(map.size() + " különböző szó:\n" + map);
}
}
Végeredmény:
4
különböző szó:
{be=2, not=1, or=1, to=2}
Ha pedig az eredeti (értsd: az előfordulási) kulcssorrendre vagyunk kíváncsiak, akkor LinkedHashMap-et használjunk:
import
java.util.*;
public class Main {
public static void main(String args[]) {
Map<String, Integer> map = new LinkedHashMap<String,
Integer>();
String [] bemenetiTomb = {"to", "be", "or", "not", "to",
"be"};
for(int i = 0; i < bemenetiTomb.length; i++) {
Integer gyakorisag = map.get(bemenetiTomb[i]);
map.put(bemenetiTomb[i], (gyakorisag
== null ? 1 : gyakorisag + 1));
}
System.out.println(map.size() + " különböző szó:\n" + map);
}
}
Végeredmény:
4
különböző szó:
{to=2, be=2, or=1, not=1}