Kolekce


Materiály

Rozhraní Collection

Collection je generické rozhraní které reprezentuje skupinu prvků známé jako elementy. Toto rozhraní nám dovoluje co nejobecnějí popsat chování všech kolekcí. Například každá kolekce má konstruktor který bere jako svůj argument Collection. Rozhraní Collection též poskytuje několik metod pro prácí s kolekcemi.

Základní metody

Pokročilé metody

Procházení kolekcí

for-each

    
    for (Object o : collection) {
        System.out.print(o)
    }
    

Iterátory

    
    public interface Iterator<E> {
        boolean hasNext();
        E next();
        void remove(); //Volitelná
    }

    static void filter(Collection<?> c) {
        for (Iterator <?> it = c.iterator(); it.hasNext();) {
            if (condition(it.next()) {
                it.remove();
            }
        }
    }
    

Set

Rozhraní Set reprezentuje kolekci která neobsahuje duplicitní prvky. SetObsahuje pouze metody které poskytuje rozhraní Collection a přidává omezení, kde jsou duplicitní elementy jsou zakázány. Java poskytuje tří základní implementace rozhraní Set: HashSet, TreeSet, and LinkedHashSet.

    
    //Deklarace množiny

    Set<Integer> integers = new HashSet<>(); //Doporučené

    HashSet<Integer> integers = new HashSet<>(); // Nedoporučuje se

    Set<Integer> i = new HashSet<Integer>() {{
        add(1);
        add(6);
    }};

    Set<Integer> i = new HashSet<>(Arrays.asList(1,2,3,4,5));


        //Použití - zjištení slov vyskytujících se v textu.

    public class FindDups {

    public static void main(String[] args) {
        String[] s = {"i", "came", "i", "saw", "i", "left"};

        Set<String> set = new HashSet<String>();
        for (String a : s) {
               set.add(a);
        }

        System.out.println(set.size() + " distinct words: " + set); // [left, came, saw, i]

    }

}
    

Pokud do množiny chceme pridat vlastní objekty musíme implementovat metody hasCode a equals. S tím nám může pomoci IDE: Code -> Generate...

    
    public class Student {

        private String name;
        private int age;
        private int clazz;

        public Student(String name, int age) {
            this.name = name;
            this.age = age;
            this.clazz = 1;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public int getAge() {
            return age;
        }

        public void setAge(int age) {
            this.age = age;
        }

        public int getClazz() {
            return clazz;
        }

        public void setClazz(int clazz) {
            this.clazz = clazz;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            Student student = (Student) o;

            if (age != student.age) return false;
            if (clazz != student.clazz) return false;
            return name != null ? name.equals(student.name) : student.name == null;
        }

        @Override
        public int hashCode() {
            int result = name != null ? name.hashCode() : 0;
            result = 31 * result + age;
            result = 31 * result + clazz;
            return result;
        }
    }

    

Map

Map je objekt který mapuje klíč na hodnotu. Mapa nesmí obsahovat duplicitní klíče. Každý klíč se může namapovat pouze na jednu hodnotu. Všechny dostupné metody jsou k dispozici zde. V Javě jsou dostupné implementace HashMap, TreeMap a LinkedHashMap.

Vybrané metody

    
    //Deklarace Mapy

    Map<String, Integer> map = new HashMap<String, Integer>() {{
        put("One", 1);
        put("Two", 2);
    }};

    Map<String, Integer> map1 = new HashMap<>();

    System.out.println(map.keySet()); // [One, Two]
    System.out.println(map.entrySet()); // [One=1, Two=2]
    System.out.println(map.values()); // [1, 2]

    

Queue

Rozhraní které reprezentuje frontu. Třída LinkedList implementuje rozhraní Queue a obsahuje mino jiné i operace add pro přidání prvku a poll pro získání prvku ze začátku fronty. Speciálním případem fronty je prioritní fronta PriorityQueue. Prvky jsou ve frontě třízeny pomocí komparatoru Comparator.

Vybrané Operace

    
    Queue<Integer> queue = new LinkedList<>();

    queue.add(1);
    queue.add(2);
    queue.add(3);

    System.out.println(queue.poll()); // 1
    System.out.println(queue.poll()); // 2

    PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();

    priorityQueue.add(6);
    priorityQueue.add(10);
    priorityQueue.add(4);

    System.out.println(priorityQueue.peek()); // 4
    

Dequeue

Reprezentuje frontu u které můžeme pridávát a odebírat prvky na začátku i na konci fronty. Java obsahuje dvě implementace LinkedList a ArrayDeque. Implementace pomocí LinkedList je flexibilnější než ArrayDeque. Implementuje všechny volitelné metody a může obsahovat prvky které jsou null. ArrayDeque má efektivnějsí vkládání a získávání prvků.

    
    Deque<Integer> deque = new LinkedList<>();
    Deque<Integer> arrayDeque = new ArrayDeque<>();

    deque.add(10);
    deque.add(13);
    deque.add(14);

    System.out.println(deque.peekFirst()); // 10
    System.out.println(deque.peekLast());  // 14
    

Úkoly

  1. Vytvořte množinu (Set) bodů (použijte třídu Point) a přesvědčte se, zda-li obsahuje duplicity. (Body zvolte tak, aby minimálně dva měly stejné souřadnice). Rozšiřte třídu Point z minulých cvičení tak, aby vhodně překryla metody Object.equals a Object.hashCode. Znovu Vytvořte stejnou množinu bodů a přesvědčte se, že neobsahuje duplicity.

  2. Implementujte statickou metodu Map<String, Integer> freq(String s), která vrací četnost slov v daném textu, mezery, čísla a interpunkci ignorujte, tj. chápejte je jako oddělovače slov.

  3. Implementujte statickou metodu Map<String, Integer> freqIgnoreCase(String s), která se chová stejně jako metoda freq, ale nerozlišuje velká a malá písmena.

  4. Implementuje jednoduchou RPN kalkulačku. Implementujte ji jako metodu double rpnCalc(String expr), kde jako argument bude předaný výraz v postfixové notaci (např. "1 2 3 + +" nebo "1 32 + 42 * 5 + 66 -") a na výstupu bude hodnota výrazu. Kalkulačka by měla fungovat následovně. Výraz je rozložen na jednotlivé atomy a potom je procházen zleva doprava. Pokud je nejlevější prvek číslo, je jeho hodnota uložena na zásobník, je-li to operátor, jsou odebrány ze zásobníku dvě hodnoty a je provedena příslušná operace. Výsledná hodnota je uložena na zásobník. Pro jednoduchost uvažujme pouze celá čísla a binární operace +, -, *, /.

  5. Rozšiřte předchozí úkol tak, aby metoda double rpnCalc(String expr, Map<String, Integer> variables) měla ještě jeden argument představující vazby proměnných. Pokud bude nalezen atom představující proměnnou, bude příslušná hodnota uložena na zásobník. Např. "1 foo +" přečte hodnotu "foo" z argumentu variables.

Úkoly posílejte na email r.vyjidacek@gmail.com s předmětem ZP3JV06. Termín odevzdání do půlnoci 8. 11. 2017. Odevzdávejte pouze zdrojové kódy v archivu zip.