Gyakorlati alapok III.

Lista (List)


Ismételjük meg az egyik előző fejezet legfontosabb megállapításait:

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

A List tartalmazhat többszörös elemeket, az elemek tárolása legtöbbször tömbszerűn, szekvenciálisan történik, de mivel az elempozíciók indexelve vannak, bármelyik listaelem kiválasztható, módosítható.

 

Valós életből vett példák: pizzafutár rendelési címei, GPS-útvonalterv. (Vegyük észre, hogy ez sok esetben, mint fordított listabejárás visszafelé is működhet!)
 

Mivel Set és List a Collection, mint közös "szülő" miatt rendkívül közeli rokonságot mutatnak egymással, ezért  csak a List néhány további, a Set-től különböző tulajdonságát vizsgáljuk meg. A Set-tel ellentétben a List-ben a következő metódusok jelennek meg:

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

2 db List akkor egyenlő, ha bennük ugyanazon elemek ugyanolyan sorrendben követik egymást.

 

A listaműveletek vizsgálatakor érdemes kiindulnunk a List egy nagyon hasznos, továbbspecializált típusából, ez a tömblista (ArrayList). Erről a típusról már részletesen írtam egy korábbi fejezetben, jóval a JCF fejezetcsomag születése előtt. Mivel számos értékes információt tartalmaz, a fejezet tartalmát egy az egyben, dőlt betűformátumban ide helyezem át.

 

Sok programozási esetben hátrány, hogy egy tömb létrehozásakor előre meg kell adnunk a tömb méretét, hiszen meglehet: ezt nem is tudjuk előre. A Java-nyelv viszonylatában már korán felmerült az igény egy olyan típusú tömbstruktúra megalkotására, amely "automatizált" tulajdonságokkal és praktikus, beépített függvényekkel rendelkezik, hogy minél kevesebbet kelljen foglalkoznunk magával a tömb adminisztratív kezelésével. Mivel az egyik leggyakrabban alkalmazott műveletek a listaműveletek, kézenfekvő volt a tömb és a lista előnyös tulajdonságainak egyesítése...

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

...így jött létre a rendkívül dinamikus tulajdonságokkal rendelkező, éppen ezért nagyon jól kezelhető tömblista (arraylist).

 

Létrehozása (majdnem) a tömbhöz hasonlóan történik, azzal a kis különbséggel, hogy a tömblista használatához szükséges, előre gyártott rutinok könyvtárát is be kell importálnunk (import java.util.ArrayList;):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;


public class Main {
public static void main(String args[]) {
    ArrayList<String> tomblista = new ArrayList<String>();
    }
}
 

A tömblista, mint objektum voltaképpen az alábbi szabványos deklaráció után születik meg...

 

ArrayList<String> tomblista = new ArrayList<String>();
 

...ahol a deklaráció szigorú követelményeinek egyetlen kivétele a tömblista neve (itt tomblista), amely a szokásos névadási konvenciók figyelembevételével bármi lehet.

 

Java 7v verzióban és felfelé a 2. típusdeklaráció (itt <String>) elmaradhat:

 

ArrayList<String> tomblista = new ArrayList<>();
 

Ekkor tehát egy olyan String típusú tárolóobjektum jön létre, amelynek ugyan van egy kezdeti tárolókapacitása (a tömblista valójában szintén tömböt használ fel a tároláshoz), ám az további méretadminisztráció nélkül, dinamikusan változik. (Itt jegyzem meg, hogy a statikus méretű tömbök esetében ezt meg sem tudjuk tenni.)  Ezután a tömblista a beépített függvények segítségével menedzselhető. Nézzünk meg néhányat közülük 1-1 jellemző példán keresztül:

 

add() - tömblista-elem hozzáadása

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya");
    System.out.println(tomblista);
    }
}

 

Végeredmény:

[Cirbolya, és , Borbolya]

 

Észrevehetjük, hogy a tömblista-elemek kiírása is alapjában véve egyszerűvé vált, egyszerű, formázatlan kiíráshoz alapjában véve nem szükséges for ciklust használnunk.

 

remove(index) - törli a paraméterként megadott indexen lévő tömblista-elemet

 

Az alábbi futtatható Java-kódban a tömblista 1. indexén lévő " és " stringet töröljük (emlékezzünk vissza, hogy az indexelés mindig 0-val kezdődik!):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya");
    tomblista.remove(1);
    System.out.println(tomblista);
    }
}

 

Végeredmény:

[Cirbolya, Borbolya]

 

clear() - törli az összes tömblista-elemet

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya");
    tomblista.clear();
    System.out.println(tomblista);
    }
}

 

Végeredmény:

[]

 

clone() - másolatot készít (klónozza) a tömblistát

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya");
    System.out.println(tomblista.clone() == tomblista);
    System.out.println(tomblista.clone().equals(tomblista));
    }
}
 

Végeredmény:

false

true

 

Fontos kihangsúlyozni, hogy a clone() függvény nem duplikálja fizikailag az objektumot, hanem csak az elemek memóriacímeit tárolja el egy új objektumban. Ezt onnan állapíthatjuk meg, hogy tartalmi összehasonlításkor (equals() függvény) true-t kapunk (a 2 objektum tartalmilag valóban azonos), fizikai összehasonlításkor viszont (==) false-t, amely azt mutatja, hogy az utóbbi esetben a memóriacímek lettek összehasonlítva (amelyek nyilvánvalóan különbözőek).

 

Néhány további függvény:

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya");
    System.out.println(tomblista.isEmpty());
    System.out.println(tomblista.size());
    System.out.println(tomblista.get(2));
    System.out.println(tomblista.indexOf("Cirbolya"));
    }
}
 

Végeredmény:

false

3

Borbolya

0

 

A tömblista-elemek kiírása tehát alapjában véve egyszerűvé vált, ám komolyabb műveletek elvégzéséhez még mindig iterálnunk kell. A probléma a for ciklus fejléce...

 

for (i = kezdőérték; i <= végérték; léptetés)

 

...mivel a tömblista mérete dinamikusan változik, azaz a fejléc adatait csak elég nehézkesen tudjuk beállítani (hiszen megállapítható a size() függvénnyel, lásd a fenti kódban).

 

A megoldás már a Java alkotóinak is eszébe jutott: ez egy egyszerűsített fejlécű for ciklus, amely csak az objektum nevét és típusát tartalmazza:

 

for (String element : tomblista)

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya");
    for (String element : tomblista) {
        System.out.print(element);
        }
    }
}
 

Végeredmény:

Cirbolya és Borbolya

 

Természetesen az iteráció "klasszikus" for ciklussal is megoldható, igaz, kissé döcögősebben: 2 db beépített függvényt is fel kellett használnunk (size() és get()):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya,");
    tomblista.add(" Moha");
    tomblista.add(" és ");
    tomblista.add("Páfrány");
    for (int i = 0; i < tomblista.size(); i++) {
        System.out.print(tomblista.get(i));
        }
    }
}
 

Végeredmény:

Cirbolya és Borbolya, Moha és Páfrány

 

Végezetül nézzük meg a fenti Java-kód egyszerűsített fejlécű ciklus-megoldását:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 

 

import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
    ArrayList<String> tomblista = new ArrayList<String>();
    tomblista.add("Cirbolya");
    tomblista.add(" és ");
    tomblista.add("Borbolya,");
    tomblista.add(" Moha");
    tomblista.add(" és ");
    tomblista.add("Páfrány");
    for (String element : tomblista) {
        System.out.print(element);
        }
    }
}

 

Végeredmény:

Cirbolya és Borbolya, Moha és Páfrány

 

Folytassuk tovább még mindig az ArrayList típussal!

 

Először nézzünk meg 1 egyszerű, Integer típusú listalétrehozást, amely során megpróbálkozunk duplikált elembevitellel is (4-4):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista = new ArrayList<Integer>();
    lista.add(1);
    lista.add(2);
    lista.add(3);
    lista.add(4);
    lista.add(4);
    lista.add(5);
    System.out.println(lista);
    }
}
 

Végeredmény:
[1, 2, 3, 4, 4, 5]

 

A duplikált elembevitel sikeres volt, hiszen az azonos elemek külön indexre kerültek, tehát egyedi hozzáférésük biztosított. Ezt a már említett indexOf()  és lastIndexOf() metódusokkal tudjuk leellenőrizni:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista = new ArrayList<Integer>();
    lista.add(1);
    lista.add(2);
    lista.add(3);
    lista.add(4);
    lista.add(4);
    lista.add(5);
    System.out.println(lista);
    System.out.println("4 első előfordulása a(z) " + lista.indexOf(4) + ". indexen.");
    System.out.println("4 utolsó előfordulása a(z) " + lista.lastIndexOf(4) + ".     indexen.");
    }
}

 

Végeredmény:
[1, 2, 3, 4, 4, 5]
4 első előfordulása a(z) 3. indexen.
4 utolsó előfordulása a(z) 4. indexen.
 

Az alábbi kódban a szintén új set() és get() metódusok alapszintű működését tanulmányozhatjuk. A listafeltöltés során "rossz", nem növekvő sorrendben adagoltuk az elemeket, amelyet egy egyszerű adatcsereberével (Hogyan cseréljünk meg kezeinkben 2 teli poharat? (adatcserebere) című fejezet), az említett metódusok segítségével javítunk (swap).

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista = new ArrayList<Integer>();
    lista.add(1);
    lista.add(2);
    lista.add(3);
    lista.add(5);
    lista.add(4);
    System.out.println("Lista swap előtt:\n" + lista);
    Integer ideiglenes = lista.get(3);
    lista.set(3, lista.get(4));
    lista.set(4, ideiglenes);
    System.out.println("Lista swap után:\n" + lista);
    }
}

 

Végeredmény:
Lista swap előtt:
[1, 2, 3, 5, 4]
Lista swap után:
[1, 2, 3, 4, 5]

 

A következő, futtatható Java-kódban listák összeillesztése fog történni az addAll() metódus segítségével. A 2 db lista feltöltését 1 lendületben, for ciklus bevetésével menedzseljük:

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista1 = new ArrayList<Integer>();
    List<Integer> lista2 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        if(i <= 5) {
            lista1.add(i);
            continue;
            }
        lista2.add(i);
        }
    System.out.println("1. lista kezdetben: " + lista1);
    System.out.println("2. lista kezdetben: " + lista2);
    lista1.addAll(lista2);
    System.out.println("1. lista listaillesztés után: " + lista1);
    }
}

 

Végeredmény:
1. lista kezdetben: [1, 2, 3, 4, 5]
2. lista kezdetben: [6, 7, 8, 9, 10]
1. lista listaillesztés után: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

 

Illetve listák összeillesztésén felül lehetőségünk van tetszőleges hosszúságú részlisták létrehozására is (subList()):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista1 = new ArrayList<Integer>();
    List<Integer> lista2 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista1.add(i);
    }
    lista2 = lista1.subList(5, 9);
    System.out.println("Főlista: " + lista1);
    System.out.println("Allista: " + lista2);
    }
}

 

Végeredmény:
Főlista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Allista: [6, 7, 8, 9]

 

A következő, futtatható Java-kódban a contains() (tartalmaz-e olyan elemet?) és remove()  (elemeltávolítás) metódusok alapszintű használatát tanulmányozhatjuk.

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista1 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista1.add(i);
    }
    System.out.println("A lista elemei '10' eltávolítása előtt: " + lista1);
    if(lista1.contains(10)) {
        int index = lista1.indexOf(10);
        lista1.remove(index);
    }
    System.out.println("A lista elemei '10' eltávolítása után: " + lista1);
    }
}

 

Végeredmény:
A lista elemei '10' eltávolítása előtt: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
A lista elemei '10' eltávolítása után: [1, 2, 3, 4, 5, 6, 7, 8, 9]

 

Az alábbi 3 db futtatható Java-kódban a listák egyenlőségét ellenőrizzük le, még pedig a már említett szabály alapján:

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

2 db List akkor egyenlő, ha bennük ugyanazon elemek ugyanolyan sorrendben követik egymást.

 

Ezt a vizsgálatot háromféleképpen tudjuk megtenni, az elvárt eredményeink a következők lesznek:

  1. ugyanazon elemek ugyanolyan sorrendben követik egymást - true,

  2. ugyanazon elemek más sorrendben követik egymást - false,

  3. az elemek lényegében különböznek (már 1 eltérés is számít, annak ellenére, hogy a többi ugyanazon elem ugyanolyan sorrendben) - false.

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista1 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista1.add(i);
    }
    System.out.println("1. lista: " + lista1);

    List<Integer> lista2 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista2.add(i);
    }
    System.out.println("2. lista: " + lista2);
    System.out.println("Egyenlő a 2 lista? " + "\n" + lista1.equals(lista2));
    }
}

 

Végeredmény:
1. lista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2. lista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Egyenlő a 2 lista?
true

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista1 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista1.add(i);
    }
    System.out.println("1. lista: " + lista1);

    List<Integer> lista2 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista2.add(i);
    }
    lista2.set(9, 9);

    lista2.set(8, 10);
    System.out.println("2. lista: " + lista2);
    System.out.println("Egyenlő a 2 lista? " + "\n" + lista1.equals(lista2));
    }
}

 

Végeredmény:
1. lista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2. lista: [1, 2, 3, 4, 5, 6, 7, 8, 10, 9]
Egyenlő a 2 lista?
false

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
public static void main(String[] args) {
    List<Integer> lista1 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista1.add(i);
    }
    System.out.println("1. lista: " + lista1);

    List<Integer> lista2 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista2.add(i);
    }
    lista2.set(9, 9);
    System.out.println("2. lista: " + lista2);
    System.out.println("Egyenlő a 2 lista? " + "\n" + lista1.equals(lista2));
    }
}

 

Végeredmény:
1. lista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2. lista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 9]
Egyenlő a 2 lista?
false

 

A JCF további, nagyon érdekes és hasznos metódusokkal szolgálhat nekünk a List felhasználásakor:

Nézzünk meg minderre egy egyesített Java-kódot (a metódusok nem feltétlenül a fenti sorrendben fogják követni egymást):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

 

public class Main {
public static void main(String[] args) {
    List<Integer> lista = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista.add(i);
    }
    System.out.println("Alaplista: " + lista);
    Collections.shuffle(lista);
    System.out.println("Lista + shuffle(): " + lista);
    Collections.sort(lista);
    System.out.println("Lista + sort(): " + lista);
    Collections.reverse(lista);
    System.out.println("Lista + reverse(): " + lista);
    Collections.reverse(lista);
    Collections.rotate(lista, 5);
    System.out.println("Lista + rotate() 5-tel jobbra: " + lista);
    Collections.sort(lista);
    Collections.swap(lista, 0, 9);
    System.out.println("Lista + swap() első és utolsó elem között: " + lista);
    Collections.fill(lista, 0);;
    System.out.println("Lista + fill() 0 értékkel: " + lista);
    Collections.replaceAll(lista, 0, 10);
    System.out.println("Lista + replaceAll() 0 érték felülírása 10 értékkel: " + lista);

    List<Integer> lista2 = new ArrayList<Integer>();
    for(int i = 1; i <= 10; i++) {
        lista2.add(i);
    }

    System.out.println("2. Lista: " + lista2);
    Collections.copy(lista2, lista);
    System.out.println("2. Lista + copy() másolás után: " + lista2);
    }
}

 

Végeredmény:
Alaplista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Lista + shuffle(): [4, 10, 7, 8, 9, 3, 6, 1, 2, 5]
Lista + sort(): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Lista + reverse(): [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Lista + rotate() 5-tel jobbra: [6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
Lista + swap() első és utolsó elem között: [10, 2, 3, 4, 5, 6, 7, 8, 9, 1]
Lista + fill() 0 értékkel: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Lista + replaceAll() 0 érték felülírása 10 értékkel: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]

2. lista: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2. Lista + copy() másolás után: [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]