Kurs programowania - kolekcje

Podobne dokumenty
Wykład 3 Składnia języka C# (cz. 2)

Języki i metodyka programowania. Język C# pętle, sterowanie, wyjątki

Programowanie obiektowe

Laboratorium z przedmiotu Programowanie obiektowe - zestaw 04

Kiedy potrzebne. Struktura (rekord) Struktura w języku C# Tablice struktur. struktura, kolekcja

Wykład 4. Klasa List Kolejki Stosy Słowniki

Opis zagadnieo 1-3. Iteracja, rekurencja i ich realizacja

Rozdział 4 KLASY, OBIEKTY, METODY

Metody Metody, parametry, zwracanie wartości

Podstawy programowania. Podstawy C# Tablice

Lista, Stos, Kolejka, Tablica Asocjacyjna

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

java.util.* :Kolekcje Tomasz Borzyszkowski

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Ćwiczenie 3 stos Laboratorium Metod i Języków Programowania

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

PARADYGMATY PROGRAMOWANIA Wykład 4

Materiał Typy zmiennych Instrukcje warunkowe Pętle Tablice statyczne Wskaźniki Tablice dynamiczne Referencje Funkcje

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Programowanie w języku Java. Kolekcje

Szablony klas, zastosowanie szablonów w programach

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Dziedziczenie. Tomasz Borzyszkowski

Podstawy programowania skrót z wykładów:

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Programowanie obiektowe i zdarzeniowe

Pętle i tablice. Spotkanie 3. Pętle: for, while, do while. Tablice. Przykłady

Lab 9 Podstawy Programowania

IMIĘ i NAZWISKO: Pytania i (przykładowe) Odpowiedzi

PHP: bloki kodu, tablice, obiekty i formularze

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk. Wydział Inżynierii Metali i Informatyki Przemysłowej

Programowanie obiektowe

Temat: Dynamiczne przydzielanie i zwalnianie pamięci. Struktura listy operacje wstawiania, wyszukiwania oraz usuwania danych.

Podstawy programowania obiektowego

Języki i techniki programowania Ćwiczenia 4 Wzorce

dr inż. Piotr Czapiewski Tworzenie aplikacji w języku Java Laboratorium 1

- - Ocena wykonaniu zad3. Brak zad3

Wykład 4: Klasy i Metody

Programowanie obiektowe

ZASADY PROGRAMOWANIA KOMPUTERÓW

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

E S - uniwersum struktury stosu

Algorytmy i. Wykład 3: Stosy, kolejki i listy. Dr inż. Paweł Kasprowski. FIFO First In First Out (kolejka) LIFO Last In First Out (stos)

Klasy cd. Struktury Interfejsy Wyjątki

Szablony funkcji i klas (templates)

Podstawy Programowania C++

Podstawy obiektowości

Klasy. dr Anna Łazińska, WMiI UŁ Podstawy języka Java 1 / 13

msgbox("akcja: Początek, argument: " + argument.tostring()); Thread.Sleep(1000); //opóźnienie msgbox("akcja: Koniec"); return DateTime.Now.

TEMAT : KLASY DZIEDZICZENIE

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Język JAVA podstawy. wykład 2, część 1. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Projektowanie aplikacji internetowych laboratorium

Pętle. Dodał Administrator niedziela, 14 marzec :27

Programowanie komputerowe. Zajęcia 3

Programowanie obiektowe - 1.

1 Podstawy c++ w pigułce.

Programowanie w środowiskach graficznych. Wykład 3 Język C#

2. Klasy cz. 2 - Konstruktor kopiujący. Pola tworzone statycznie i dynamicznie - Funkcje zaprzyjaźnione - Składowe statyczne

Dokumentacja do API Javy.

Wykład 8: klasy cz. 4

Współbieżność w środowisku Java

Dawid Gierszewski Adam Hanasko

Myśl w języku Python! : nauka programowania / Allen B. Downey. Gliwice, cop Spis treści

Programowanie obiektowe. Dr hab. Inż. Marta Gładysiewicz-Kudrawiec Pokój 229 A1 Operatory new delete pliki-odczyt

Języki i metody programowania Java INF302W Wykład 3 (część 1)

Materiały do zajęć VII

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Wykład 7: Pakiety i Interfejsy

Podstawy programowania, Poniedziałek , 8-10 Projekt, część 1

Definiowanie własnych klas

Wykład 8: Obsługa Wyjątków

INFORMATYKA W SZKOLE. Podyplomowe Studia Pedagogiczne. Dr inż. Grażyna KRUPIŃSKA. D-10 pokój 227

Tabela wewnętrzna - definicja

Zaawansowane programowanie w języku C++ Klasy w C++

Tablice. Jones Stygar na tropie zmiennych

Wstęp do programowania

Część 4 życie programu

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Algorytmy i złożoności. Wykład 3. Listy jednokierunkowe

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Definicje klas i obiektów. Tomasz Borzyszkowski

Podstawy informatyki. Informatyka stosowana - studia niestacjonarne. Grzegorz Smyk

Celem tego projektu jest stworzenie

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Programowanie zaawansowane

Podstawy Programowania Obiektowego

Transkrypt:

Kurs programowania - kolekcje Tablice to istotny element niemal każdego języka programowania, ale oprócz tablic istnieją także inne struktury danych: listy, kolejki, drzewa i różne ich podtypy. Wszystkie one, łącznie z tablicami, zostały nazwane w C# kolekcjami. Co więcej, większość typowych kolekcji (a także kilka dodatkowych) została zaimplementowana w platformie.net i jest gotowa do użycia. Definicja tablicy w dowolnym języku programowania jest zawsze taka sama: tablica to struktura, która przechowuje elementy tego samego typu. Inną sprawą jest jej implementacja. W C# zrobiono to w taki sposób, aby niemożliwe było popełnienie często występującego w C/C++ błędu, w którym dochodzi do odczytu lub zapisu danych za zadeklarowanym obszarem tablicy. W C# indeksy są kontrolowane przez klasę implementującą tablicę. O ile w C/C++ tablica to po prostu fragment pamięci z adresem zapamiętanym we wskaźniku do pierwszego elementu, to w C# jest ona instancją klasy System.Array. Oznacza to, że tablica jest obiektem. Dzięki temu możliwe jest łatwe kontrolowanie tego, czy indeksy nie są mniejsze od zera lub czy nie są większe od rozmiaru tablicy (minus jeden). Kolekcja List Przyjrzyjmy się teraz najczęściej wykorzystywanej kolekcji System.Collections. Generics.List, czyli implementacji listy. Należy ona do grupy typów ogólnych (ang. generic types), nazywanych też typami parametrycznymi. Ma tę zaletę w porównaniu ze zwykłą tablicą ( System.Array ), że liczba elementów może być zmieniana już po utworzeniu listy można dodawać elementy na koniec, wstawiać do środka i usuwać dowolnie wybrany element. Jednocześnie możliwy jest dostęp do dowolnego elementu, tak samo jak w przypadku tablicy. W poniższym przykładzie (listing 3.26) utworzymy kolekcję tego typu składającą się ze stu losowo wybranych liczb całkowitych. Następnie do jej końca dodamy dziesięć liczb o wartości 0, a do środka wstawimy kolejnych pięć o wartości 1. Wreszcie na pierwszej pozycji ustawimy liczbę 1. Na koniec usuniemy wszystkie te liczby, które są większe od 20, i posortujemy resztę. int rozmiar = 30; List<int> l = new List<int>(new int[rozmiar]); for (int i = 0; i < rozmiar; i++) l[i] = r.next(100); l.addrange(new int[10]); int[] i5 = -1, -1, -1, -1, -1 ; l.insertrange(rozmiar / 2, i5); l.insert(0, 1); // tu kryją się błędy

for (int i = 0; i < rozmiar; i++) if (l[i] > 20) l.removeat(i); l.sort(); string s = "Elementy listy: "; foreach (object ai in l) s += ai.tostring() + " "; Console.WriteLine(s); Błędy, i to aż trzy, kryją się w pętli usuwającej liczby większe niż 20. Pierwszy polega na tym, że po wcześniejszych manipulacjach lista nie ma już wielkości określonej przez zmienną rozmiar. W tej chwili jest ona równa rozmiar+10+5. Możemy więc albo kontrolować na bieżąco wartość zmiennej rozmiar, zmniejszając ją w iteracji, gdy usuwany jest element z listy, albo co jest zdecydowanie lepszym rozwiązaniem wymusić sprawdzanie rzeczywistego rozmiaru listy, odczytując właściwość List<>.Count, w tym przypadku l.count Pierwsza poprawka: // lepiej, ale nadal z błędem for(int i=0;i<l.count;i++) if (l[i]>20) l.removeat(i); Drugi, poważniejszy błąd kryje się w samej pętli. Otóż usuwając w niektórych jej iteracjach elementy listy, zmniejszamy jej rozmiar. Jeżeli zatem na liście jest więcej niż piętnaście liczb większych od 20, a zapewne tak jest, rozmiar listy zmniejszy się i znajdzie się poniżej wartości określonej przez wielkość zapamiętaną w zmiennej rozmiar, a w efekcie kolejne iteracje będą musiały się skończyć zgłoszeniem wyjątku System.ArgumentOutOfRangeException (z ang. argument poza zakresem). Nie pomoże używanie pętli foreach, bo ona również nie sprawdza, czy w wyniku wykonania iteracji zmienił się rozmiar kolekcji ustalony podczas inicjacji pętli. To jednak nie wszystko. W pętli kryje się również trzeci błąd logiczny. W razie spełnienia warunku l[i]>20 usuwany jest element listy na pozycji i, co doprowadza do zmniejszenia listy o 1. Pętla przechodzi wówczas do następnej pozycji listy, czyli i+1. Ale po usunięciu elementu i obecny element i+1 spada na pozycję i. W efekcie element ten nie jest w ogóle testowany. Należałoby więc wymusić ponowne sprawdzenie elementu o tym numerze, obniżając indeks pętli. for(int i=0;i<l.count;i++) if (l[i]>20)

l.removeat(i); i--; Kolekcja SortedList i inne słowniki Poza List w przestrzeni nazw System.Collections.Generics dostępne są także inne typowe struktury danych. Pierwsza z nich to kolejka zaimplementowana w klasie Queue. Do kolejki można dodać element tylko na końcu, a zdjąć tylko na początku. Inna popularna struktura danych to stos (klasa Stack ), tj. zbiór, z którego można zdjąć jedynie element ostatnio dołożony. Spośród innych kolekcji na uwagę zasługuje SortedList, która w odróżnieniu od omówionych wcześniej jest dwukolumnowa. Każdy element listy przechowuje bowiem klucz i wartość (właściwości Key i Value ). Pozwala to m.in. na sortowanie obu wartości według klucza, co często bywa przydatne. Podobnie zbudowane są kolekcje Dictionary i SortedDictionary. Wszystkie implementują wspólny interfejs IDictionary i dlatego często nazywane są słownikami. Typowym zastosowaniem tej kolekcji są różnego typu listy z kluczem, np. słowniki, listy zmiennych itp. W poniższym przykładzie korzystam z kolekcji SortedList z oboma parametrami typu String, wykorzystując ją do przechowywania imion i nazwisk osób, które posługują się pseudonimami. Pseudonimy będą pełniły funkcję kluczy (ang. key), a prawdziwe personalia wartości (ang. value). Wygodną właściwością kolekcji SortedList jest to, na co wskazuje jej nazwa, a więc to, że jest automatycznie sortowana zgodnie z kolejnością alfabetyczną kluczy. SortedList<string,string> artysci = new SortedList<string,string>(); artysci.add("sting","gordon Matthew Sumner"); artysci.add("bolesław Prus","Aleksander Głowacki"); artysci.add("pola Negri","Barbara Apolonia Chałupiec"); artysci.add("john Wayne","Marion Michael Morrison"); artysci.add("chico","leonard Marx"); artysci.add("harpo","arthur Marx"); artysci.add("groucho","julius Marx"); artysci.add("bono","paul Hewson"); artysci.add("ronaldo","luiz Nazario de Lima"); artysci.add("madonna","madonna Louise Veronica Ciccone"); artysci.add("gabriela Zapolska","Maria G. Śnieżko-Błocka"); string komunikat = "Zawartość listy:\n"; foreach (KeyValuePair<string, string> artysta in artysci) komunikat += artysta.key + " - " + artysta.value + "\n"; Console.WriteLine(komunikat);

Kolejka i stos Przestrzeń System.Collections.Generic zawiera również implementacje dwóch standardowych struktur danych: kolejki (ang. queue) i stosu (ang. stack). Pierwsza jest strukturą typu FIFO (ang. first in, first out) element włożony jako pierwszy może być pierwszy zdjęty. Kolejkę można sobie wyobrażać jako rurę, do której wkłada się piłki z jej jednego końca i wyjmuje z drugiego. Inaczej jest w przypadku stosu. Jest to struktura typu FILO (ang. first in, last out) element włożony jako pierwszy dostępny będzie jako ostatni. Nazwa tej struktury dobrze oddaje też to, jak można sobie ją wyobrażać jako stos np. kartek. To, co położymy na stosie jako pierwsze, będzie przykrywane przez następne elementy i tym samym dostępne dopiero, gdy zdejmiemy wszystkie położone później. int rozmiar = 10; Queue<int> kolejka = new Queue<int>(rozmiar); Stack<int> stos = new Stack<int>(rozmiar); kolejka.enqueue(i); stos.push(i); string s = "Elementy zdjęte z kolejki (" + kolejka.count + " elementów): "; s += kolejka.dequeue().tostring() + " "; Console.WriteLine(s); s = "Elementy zdjęte ze stosu (" + stos.count + " elementów): "; s += stos.pop().tostring() + " "; Console.WriteLine(s); Tablice jako argumenty metod oraz metody z nieokreśloną liczbą argumentów C# dopuszcza definiowanie metod, w których liczba argumentów nie jest z góry określona. Możliwość ta nie jest może wykorzystywana zbyt często we własnym kodzie, ale czasem może być bardzo przydatna. Dobrym przykładem jest jej użycie w konstruktorach klas używanych w technologii LINQ to XML (rozdział 4.). Poniżej przedstawię prosty przykład takiej metody. static private int Suma(int[] lista) Console.WriteLine("Liczba argumentów: " + lista.length.tostring()); int suma = 0; foreach (int liczba in lista) suma += liczba; return suma;

Do takiej metody przekazywana jest tablica liczb typu int, tzn. jej wywołanie powinno wyglądać następująco: int suma = Suma(new int[] 1, 2, 3 ); Console.WriteLine("Suma: " + suma.tostring()); Gdy jednak zmienimy sygnaturę metody, dodając przed typem tablicowym słowo kluczowe params (listing 3.33), możemy ją wywoływać tak, że argumentami są elementy tablicy dowolna ilość liczb typu int : int suma = Suma(1, 2, 3) static private int Suma(params int[] lista) Console.WriteLine("Liczba argumentów: " + lista.length.tostring()); int suma = 0; foreach (int liczba in lista) suma += liczba; return suma; ; Kompilator sam utworzy z nich tablicę. Takie przekazanie elementów tablicy nie jest jednak obowiązkowe. Nadal możemy jako argumentu użyć tablicy, a nawet kolekcji będącej wynikiem zapytania LINQ, które na tablicę można skonwertować. Co więcej, ponieważ argumentem metody jest tablica, a więc w istocie referencja do niej (tablice, jak już wiemy, są typem referencyjnym), możliwa jest zmiana elementów tychże i w efekcie zwrot wartości przez argumenty, tak jak w przypadku słów kluczowych ref i out. Słowo kluczowe yield Wyobraźmy sobie metodę, której zadaniem jest generowanie pewnego zbioru elementów. Przyjmijmy, że chodzi o zbiór liczb pseudolosowych to jednak ma naprawdę drugorzędne znaczenie. Najbardziej naturalny przepis na taką metodę to: zadeklarować tablicę liczb całkowitych, utworzyć instancję klasy Random, w pętli zapełnić tablicę liczbami losowymi i całość zwrócić przez wartość funkcji. static int[] metoda(int rozmiar) int[] wynik = new int[rozmiar]; wynik[i]=r.next(); return wynik;

static void Main(string[] args) int[] ti = metoda(10); foreach (int element in ti) Console.WriteLine(element.ToString()); Korzystając z tego schematu, można łatwo przygotować funkcję zwracającą np. kolejne potęgi dwójki lub kolekcję przycisków. Zmieni się tylko typ kolekcji i zapełniająca ją pętla. W C# istnieje jednak stosunkowo mało znana alternatywa dla tego schematu słowo kluczowe yield dodane do języka w wersji 2.0. IEnumerable<int> metoda(int rozmiar) yield return r.next(); yield break; static void Main(string[] args) int[] ti = metoda(10).toarray(); foreach (int element in ti) Console.WriteLine(element.ToString()); Zwróćmy uwagę, że zmienił się typ wartości zwracanej przez metodę. Zamiast tablicy jest nim teraz kolekcja policzalnych elementów typu IEnumerable<int>. Słowo kluczowe yield pojawia się w metodzie w dwóch kontekstach. W pierwszym występuje przed słowem kluczowym return. Zwróćmy uwagę, że za słowem return nie ma kolekcji, która przecież jest typem wartości zwracanej przez metodę, a jedynie są jej elementy. Co więcej, konstrukcja yield return znajduje się wewnątrz pętli. Ale właśnie na tym polega innowacja instrukcja yield return nie kończy działania metody tak jak samo return, a jedynie dodaje występujący po niej element do niejawnie zdefiniowanej kolekcji. Kolekcja ta budowana jest dopóty, dopóki wątek nie natrafi na instrukcję yield break. Jest to sygnał do przerwania zbierania elementów. W naszym prostym przykładzie instrukcja ta wykonywana jest po zakończeniu pętli. Kolekcja zwracana przez metodę nie musi mieć z góry ustalonego rozmiaru. Jest tworzona dynamicznie, wobec tego proces jej budowania można przerwać w dowolnym momencie. Wersja tradycyjna: IEnumerable<int> metoda(int próg) List<int> wynik=new List<int>();

int los; do los = r.next(15); wynik.add(los); while (los < próg); return wynik.asenumerable<int>(); Wersja korzystająca ze słowa kluczowego yield: IEnumerable<int> metoda(int próg) int los; do los = r.next(15); yield return los; while (los < próg); yield break; Caller Information W C# 5.0 pojawiła się również możliwość uzyskania w metodzie informacji o miejscu, z którego nastąpiło jej wywołanie. Możemy uzyskać informacje o nazwie metody wywołującej, ścieżce do pliku, w którym owa metoda jest zdefiniowana, i numerze linii w pliku, w której znajduje się instrukcja wywołania. Informacje uzyskane w ten sposób mogą być szczególnie przydatne przy śledzeniu błędów aplikacji internetowych. Najwygodniej rejestrować je wówczas za pomocą klasy System.Diagnostics.Trace. static public void PokazInformacje( string zwyklyargument, [CallerMemberName] string membername = "", [CallerFilePath] string sourcefilepath = "", [CallerLineNumber] int sourcelinenumber = 0) Console.WriteLine("Informacje o miejscu wywołania metody:"); Console.WriteLine("nazwa elementu składowego: " + membername); Console.WriteLine("ścieżka pliku z kodem źródłowym: " + sourcefilepath); Console.WriteLine("numer linii, w której nastąpiło wywołanie: " + sourcelinenumber);