250 likes | 375 Views
Uzupełnienie. W OS zmienne indeksowane są utożsamiane ze zwykłymi, więc przykład z MonitoredArray trzeba by przerobić przeliczając indeksy o 1. Kolekcje. Collection Bag IndexedCollection Array ByteArray Interval OrderedCollection SortedCollection String Symbol Set Dictionary
E N D
Uzupełnienie W OS zmienne indeksowane są utożsamiane ze zwykłymi, więc przykład z MonitoredArray trzeba by przerobić przeliczając indeksy o 1.
Kolekcje • Collection • Bag • IndexedCollection • Array • ByteArray • Interval • OrderedCollection • SortedCollection • String • Symbol • Set • Dictionary • Magnitude • Association • Te klasy definiują różne struktury danych. • Kategorie metod: • Przechodzenie (iterowanie) po elementach kolekcji • Szukanie konkretnego elementu w kolekcji • Dodawanie i usuwanie elementów • Pobieranie i zmienianie elementów • Konwersje: • asArray • asBag • asOrderedCollection • asSet • asSortedCollection każdy element <= następny • asSortedCollection: sortBlock sortBlock określa porządek
Klasa Collection • add: newObject dodaje nowy obiekt do kolekcji • addAll: aCollection dodaje wszystkie obiekty z aCollection • remove: anObject ifAbsent: exceptionBlock • remove: anObject usuwają obiekt z kolekcji • removeAll: aCollection usuwa kolekcję z kolekcji • do: aBlock wykonuje aBlock dla każdego elementu z kolekcji • select: aBlock wykonuje aBlock dla każdego elementu odbiorcy, • tworząc nową kolekcję składającą się z tych • elementów odbiorcy, dla których aBlock daje true. • reject: aBlock podobnie, tworzy kolekcję z elementów, dla których • aBlock daje false • collect: aBlock wykonuje aBlock dla każdego elementu odbiorcy • i daje nową kolekcję zawierającą elementy • wyliczane przez blok (przetwarza elementy • kolekcji tworząc z wynikowych wartości nową kol.) • size liczba elementów odbiorcy • isEmpty czy kolekcja jest pusta • includes: anObject czy kolekcja (odbiorca) zawiera anObject • occurrencesOf: anObject liczba wystąpień obiektu w odbiorcy • Metody klasowe • with: anObject • with: firstObject with: secondObject • with: firstObject with: secondObject with: thirdObject • withAll: aCollection • np. OrderedCollection with: $4 with: ‘abc’ with: 8
BAG (worek) • Rodzaj zbioru z powtórzeniami. Ma wszystkie metody klasy Collection. • occurrencesOf: anObject liczba powtórzeń obiektu w worku • size liczba elementów, razem z powtórzeniami • SET (zbiór) • Kolekcja bez powtórzeń i bez porządku. Ma wszystkie metody klasy • Collection, tzn. • add: anObject dodaje obiekt (teoriomnogościowo) • remove: anObject usuwa obiekt (ignorowane jeśli nie ma) • remove: anObject ifAbsent: aBlock • usuwa obiekt, jeżeli go nie ma, to wykonuje blok • size liczba elementów w zbiorze • includes: anObject czy element należy do zbioru • do: aBlock wykonuje blok dla każdego elementu IndexedCollection (kolekcje indeksowane) Klasa abstrakcyjna obejmująca kolekcje dające indeksowany dostęp do elementów. Indeksy wyznaczają porządek elementów w kolekcji. Oprócz metod z klasy Collection, są tu m. in. first pierwszy element kolekcji last ostatni element kolekcji at: anInteger element pod indeksem anInteger at: anInteger put: anObject wstawia obiekt na istniejącą pozycję anInteger at: anInteger insert: anObject wstawia obiekt na pozycję anInteger Najważniejsze kolekcje indeksowane to Array (tablice), String (napisy) i OrderedCollection (odpowiednik list).
Słownik (Dictionary) • Reprezentuje zbiór elementów dostępnych poprzez klucze. • Elementami słownika są obiekty klasy Association - pary • (klucz, wartość). • Wartości mogą się powtarzać, ale klucze są niepowtarzalne. • add: anAssociation dodaje nowy element - asocjację • associationsDo: aBlock parametrem bloku będzie asocjacja • Zalecane jest działanie raczej na wartościach i kluczach, a nie na • asocjacjach: • at: aKey daje wartość związaną z kluczem aKey. • Daje nil, jeśli takiego klucza nie ma w słowniku. • at: aKey ifAbsent: aBlock jeśli klucza nie ma, wykonuje ABlock • at: aKey put: anObject wstawia parę (aKey, anObject) do • słownika. Jeśli taki klucz już jest, to • zmienia drugi element pary. • do: aBlock wykonuje blok dla każdej wartości ze słownika • keysDo: aBlock wykonuje blok dla każdej wartości ze słownika • removeAssociation: anAssociation • usuwa parę anAssociation • removeKey: aKey ifAbsent: aBlock • removeKey: aKey usuwa parę, której kluczem jest aKey • keys daje zbiór kluczy • values daje tablicę wartości • size daje liczbę par w słowniku
Kolekcja uporządkowana (OrderedCollection) • Może być użyta jako dynamiczna tablica, stos, lista lub kolejka. • , aCollection daje uporządkowaną kolekcję powstałą • przez połączenie dwóch kolekcji • add: anObject dodaje obiekt na koniec kolekcji • add: newObject after: oldObject dodaje obiekt we wskazanym • add: newObject before: oldObject miejscu (błąd gdy nie ma) • addFirst: anObject dodaje obiekt na początek kolekcji • addLast: anObject dodaje obiekt na koniec kolekcji • after: anObject ifNone: aBlock • before: anObject ifNone: aBlock • daje obiekt występujący bezp. po (przed) anObject. Jeśli anObject nie • występuje, lub jest ostatni (pierwszy) to wykonuje się aBlock. • remove: anObject ifAbsent: aBlock usuwa obiekt z kolekcji • removeFirst usuwa (i daje) pierwszy element (błąd gdy nie ma) • removeLast usuwa (i daje) ostatni element (błąd gdy nie ma) • do: aBlock wykonuje aBlock dla kolejnych elementów • ponieważ dziedziczy z IndexedCollection, to ma metody: • at: anInteger daje element występujący na pozycji anInteger • at: anInteger put: anObject • first daje pierwszy element • last daje ostatni element
Kolekcja posortowana (SortedCollection) Podklasa OrderedCollection sortBlock: aBlock tworzy nową kolekcję z określonym porządkiem new tworzy nową kolekcję z porządkiem <= Przykłady bloków sortujących: 1. sortowanie napisów według liczby samogłosek [ :a :b | (a asLowerCase select: [ :c | c isVowel ]) asSet size <= (b asLowerCase select: [ :c | c isVowel ]) asSet size ] 2. Kolejka priorytetowa - zakładamy, że elementy mają priorytet [ :a :b | a priorytet <= b priorytet ]
Przykład użycia klasy Bag Liczymy liczbę wystąpień słów na pliku. W wyniku wypisujemy listę słów (alfabetycznie) i liczbę ich wystąpień. | input wystapienia output slowo | input := NewFileStream file: 'in.dat'. output := NewFileStream createFile: 'out.dat'. wystapienia := Bag new. [(slowo := input nextWord) isNil] whileFalse: [ wystapienia add: slowo asLowerCase ]. wystapienia asSet asSortedCollection do: [ :word | output nextPutAll: word; tab; nextPutAll: (wystapienia occurrencesOf: word) printString; cr ]. input close. output close.
Słownik - przykłady • KsiążkaTelefoniczna := Dictionary new. • KsiążkaTelefoniczna • at: ‘Ania’ put: ‘36-34-22’ ; • at: ‘Jan’ put: ‘352-33-55’ ; • at: ‘Basia’ put: ‘36-34-22’. • KsiążkaTelefoniczna at: ‘Ania’ --- numer telefonu Ani • KsiążkaTelefoniczna at: ‘Tomek’ ifAbsent: [^’brak danych’] • Zbiór - przykłady • Obliczamy zbiór znaków występujących • w jednym pliku, a w drugim nie. • | set1 set2 | • set1 := Set new. • set2 := Set new. • (NewFileStream name: ‘file1.txt’) do: [ :c | set1 add: c ]. • (NewFileStream name: ‘file2.txt) do: [ :c | set2 add: c ]. • ^set1 reject: [ :c | set2 includes: c ]
Reprezentacja grafu Graf = zbiór wierzchołków Każdy wierzchołek grafu ma jakąś informację (etykietę) i uporządkowaną kolekcję (OrderedCollection) lub zbiór (jeżeli porządek jest nieistotny) wierzchołków będących sąsiadami. Jeżeli krawędzie grafu mają być etykietowane (np. jak w automacie), to można zamiast uporządkowanej kolekcji użyć słownika, którego kluczami będą etykiety, a wartościami wierzchołki grafu (sąsiedzi). Zaznaczanie wierzchołków przy obchodzeniu grafu można zrobić przez przechowywanie zbioru zaznaczonych wierzchołków.
Obchodzenie grafu wszerz • Decydujemy się na dostęp do węzłów grafu także poprzez • ich etykiety. Graf musimy zatem reprezentować jako słownik, • którego kluczami są etykiety (napisy), a wartościami węzły. • Object sublass: #Graf • instanceVariableNames: ‘ węzły’ • classVariableNames: ‘‘ • poolDictionaries: ‘‘ węzły - słownik węzłów (coś w rodzaju tablicy węzłów indeksowanej etykietami) Klasa definiująca węzły grafu. Dowiązania do sąsiadów są reprezentowane przez zbiór dowiązania. • Object sublass: #Węzeł • instanceVariableNames: ‘ etykieta dowiązania’ • ........ • “Metody klasowe “ • with: aString • “Tworzy nowy węzeł o etykiecie aString” • ^self new initialize: aString • “Metody egzemplarzowe” • initialize: aString • etykieta := aString. • dowiązania := Set new. • etykieta • ^etykieta • dołącz: węzeł • dowiązania add: węzeł
Object sublass: #Graf • instanceVariableNames: ‘ węzły’ • classVariableNames: ‘‘ • poolDictionaries: ‘‘ • “Metody klasowe “ • new • ^super new initialize • “Metody indywidualne” • initialize • węzły := Dictionary new • dodaj: et • “Dodajemy do grafu węzeł o etykiecie et i przekazujemy jako • wynik. Jeśli węzeł o takiej etykiecie już istniał, to jest wynikiem” • | nowy | • ^węzły at: et ifAbsent: • [ nowy := Węzeł with: et . węzły at: et put: nowy. • ^nowy ] • dodajWęzeł: węzeł • “Dodaje już gotowy węzeł do grafu, jeżeli nie ma jeszcze • węzła o takiej samej etykiecie; wpp. błąd “ • (węzły includesKey: węzeł etykieta) • ifTrue: [ ^self error: ‘powtórzona etykieta’] • ifFalse: [ węzły at: (węzeł etykieta) put: węzeł. ^węzeł ] • połącz: et1 z: et2 • (dodaj: et1) dołącz: (dodaj: et2) • połączWęzeł: w1 z: w2 • (dodajWęzeł: w1) dołącz: (dodajWęzeł: w2)
obejdźWszerz: startEt wykonując: aBlock • “Obchodzi graf wszerz począwszy od węzła o etykiecie • startEt, dla każdego węzła wykonując aBlock “ • ^self obejdźOdWęzła: (węzły at: startEt ifAbsent: • [ ^self error: ‘nie ma takiego węzła’] ) • wykonując: aBlock • obejdźOdWęzła: start wykonując: aBlock • “ Obchodzi graf wszerz, startując od węzła start.” • | kolejny zaznaczone kolejka | • zaznaczone := Set new. • kolejka := OrderedCollection new. • kolejka addLast: start. • zaznaczone add: start. • [ kolejka isEmpty ] whileFalse: • [ kolejny := kolejka removeFirst . • (kolejny dowiązania) do: • [ : w | (zaznaczone includes: w) • ifFalse: [ kolejka addLast: w . • zaznaczone add: w ] . • aBlock value: kolejny ] • Przykład użycia: • graf := Graf new. • graf połącz: ‘A’ z: ‘B’; • połącz: ‘A’ z: ‘C’; • połącz: ‘C’ z: ‘A’; • połącz: ‘A’ z: ‘D’; • połącz: ‘C’ z: ‘D’. • graf dodaj: ‘X’; dodaj ‘Y’. • graf obejdźWszerz: ‘A’ wykonując: • [ : w | w etykieta out ]
B A C D Przykład - Network (graf) • Sieć (Network) rozumiemy jako kolekcję wierzchołków jakoś ze • sobą powiązanych. • Object sublass: #Network • instanceVariableNames: ‘ connections’ • classVariableNames: ‘‘ • poolDictionaries: ‘‘ • Zmienne egzemplarzowa connections jest słownikiem powiązań między • wierzchołkami. Kluczami w tym słowniku są wierzchołki, wartościami • są zbiory wierzchołków powiązane z wierzchołkiem określonym • przez klucz. Elementem słownika connections, czyli parą (klucz, wartość) będzie ( wierzchołek A, zbiór { B, C, D } ) • “Metody egzemplarzowe klasy Network” • connect: nodeA to: nodeB • "Dodajemy powiązanie między wierzchołkiem A i B." • (connections • at: nodeA ifAbsent: [connections at: nodeA put: Set new]) • add: nodeB. • (connections • at: nodeB ifAbsent: [connections at: nodeB put: Set new]) • add: nodeA
initialize • "Inicjalizacja sieci." • connections := Dictionary new • printOn: aStream • "Wypisujemy graf na strumień." • connections keys asSortedCollection do: • [ :node | • node printOn: aStream. • (connections at: node) asSortedCollection do: • [ :neighbor | • aStream • cr; • nextPutAll: ' >> '. • neighbor printOn: aStream]. • aStream cr] • Chcemy znaleźć taką drogę w sieci pomiędzy dwoma wierzchołkami, • która nie prowadzi przez wierzchołki należące do danego zbioru. • pathFrom: nodeA to: nodeB avoiding: nodeSet • " Znajdujemy drogę od wierzchołka A do wierzchołka B nie • prowadzącą przez wierzchołki ze zbioru nodeSet. Wynik jest • zwracany jako nowa sieć (obiekt klasy Network )”. • | answer | • nodeSet add: nodeA. • (connections at: nodeA ifAbsent: [^nil]) do: • [ :node | • node = nodeB ifTrue: • [ ^Network new initialize connect: nodeA to: node]. • (nodeSet includes: node) ifFalse: • [ answer := self pathFrom: node to: nodeB • avoiding: nodeSet. • answer isNil ifFalse: • [ ^answer connect: nodeA to: node]]]. • ^nil!
Object sublass: #NetworkNode • instanceVariableNames: ‘ name ‘ • classVariableNames: ‘‘ • poolDictionaries: ‘‘ • “Metody indywidualne klasy NetworkNode” • <= aNode • “Porównujemy nazwy” • ^ name <= aNode name • name • ^name • name: aString • name := aString • printOn: aStream • aStream • nextPutAll: ‘Node (‘, name, ‘)’
Strumienie (Streams) Strumienie służą m.in.do komunikowania się programu z otoczeniem. Dwie wersje w OS: Object NewStream (w OS jest trochę więcej podklas NewStream) Random PositionableStream ReadStream WriteStream ReadWriteStream NewFileStream Stream (klasy Stream w OS nie będziemy używać) FileStream Zawartość strumieni jest przechowywana w postaci kolekcji.
NewStream Realizuje pojęcie strumienia sekwencyjnego atEnd czy koniec strumienia (abstr) next daje następny obiekt ze strumienia (abstr) nextPut: anObject wpisuje obiekt na bieżącą pozycję (abstr) do: aBlock wykonuje blok dla każdego elementu strumienia nextPutAll: aCol dopisuje kolekcję aCol do strumienia i daje jako wynik contents daje kolekcję będącą zawartością strumienia (abstr) do: aBlock [self atEnd]whileFalse: [aBlock value: self next] nextPutAll: aCollection aCollection isSequenceable ifTrue: [self next: aCollection size putAll: aCollection startingAt: 1] ifFalse: [aCollection do: [:v | self nextPut: v]]. ^aCollection
NewStream>nextWord nextWord | first aChar | [ self atEnd ifTrue: [ ^ nil ]. self next isAlphaNumeric ] whileFalse: []. "skip separators" first := self position. [ self atEnd ifTrue: [ ^ self copyFrom: first to: self position ]. (aChar := self next) isAlphaNumeric ] whileTrue: []. self backupOver: aChar. ^ self copyFrom: first to: self position
PositionableStream Realizuje strumień pozwalający zmieniać bieżącą pozycję on: anIndexedCollection Klasowa, tworzy nowy strumień oparty na IndexedCollection position daje bieżącą pozycję position: anInteger ustawia pozycję reset ustawia pozycję na 0 isEmpty czy strumień pusty
Random Realizuje strumień liczb pseudolosowych new Klasowa, tworzy nowy generator (uwaga - zainicjowany na podstawie zegara systemowego) next daje kolejną liczbę pseudolosową [0..1[ seed: aSmallInteger inicjalizuje generator atEnd zawsze daje false contents powoduje błąd
Strumienie plikowe • Klasy związane z plikami: • Directory • File • Tworzenie nowego obiektu klasy NewFileStream: • Otwieranie istniejącego pliku • file: aFileName • file: aFileName onError: errorBlock • file: aFileName mode: aSymbol • onError: errorBlock • Tworzenie pliku • createFile: filename • createFile: aFileName onError: errorBlock • createFile: aFileName mode: aSymbol • onError: errorBlock • Metody klasy FileStream: • close zamyka plik • flush nie zamyka, ale zapisuje zawartość na dysku • File name: name tworzy plik (File) o nazwie name • File open:name otwiera plik (File) o nazwie name
Przykład - baza danych plików • Klasa WordIndex pozwala na utworzenie bazy danych dokumentów, • umożliwiającej szybkie odszukanie wszystkich dokumentów • zawierających pewne słowa. Zakładamy, że dokumenty są plikami • tekstowymi zawierającymi słowa (ciągi znaków alfanumerycznych • oddzielonych innymi znakami). Używamy bazy danych zadając jej • pytanie zawierające kolekcję słów; w odpowiedzi otrzymujemy kolekcję • nazw (ścieżek) dokumentów zawierających wszystkie te słowa. • Np. chcemy znaleźć wszystkie dokumenty zawierające • “programowanie obiektowe”. Obiekty tej klasy (bazy danych) będą • miały dwa atrybuty: • documents - zbiór napisów reprezentujących ścieżki do plików, • których słowa są umieszczone w indeksie • words - indeks słów, słownik, którego kluczami są słowa, • a wartościami ścieżki do dokumentów zawierających te słowa • Object subclass: #WordIndex • instanceVariableNames: 'documents words ' • classVariableNames: '' • poolDictionaries: '' • “Metody klasowe klasy WordIndex” • new • ^ super new initialize • “Metody indywidualne klasy WordIndex” • initialize • "Inicjalizacja pustego indeksu." • documents := Set new. • words := Dictionary new
addWord: wordString for: pathName • "Dodaje wordString do słownika words dla dokumentu • opisanego przez pathName." • (words includesKey: wordString) • ifFalse: [words at: wordString put: Set new]. • (words at: wordString) add: pathName • addDocument: pathName • "Dodaje wszystkie słowa dokumentu opisanego przez • pathName do słownika words." • | word wordStream | • “Jeżeli dokument o tej nazwie już tu jest, to usuwamy go • i odwołania do niego ze słownika words” • (documents includes: pathName) • ifTrue: [self removeDocument: pathName]. • “Otwieramy plik” • wordStream := NewFileStream file: pathName. • documents add: pathName. • [(word := wordStream nextWord) == nil] • whileFalse: [ • self addWord: word asLowerCase for: pathName]. • wordStream close • removeDocument: pathName • "Usuwamy dokument o nazwie pathName ze słownika words” • words do: [ :docs | docs remove: pathName]. • self removeUnusedWords • removeUnusedWords • "Usuwamy wszystkie słowa, które mają puste zbiory dokumentów." • | newWords | • newWords := Dictionary new. • words associationsDo: [ :anAssoc | • anAssoc value isEmpty • ifFalse: [newWords add: anAssoc]]. • words := newWords
locateDocuments: queryWords • "Daje tablicę nazw (ścieżek) plików wszystkich dokumentów • zawierających wszystkie słowa w kolekcji queryWords." • | answer bag | • bag := Bag new. • answer := Set new. • queryWords do: [ :word | • bag addAll: (words at: word ifAbsent: [#()])]. • "bag zawiera wszystkie ścieżki dokumentów zawierających • którekolwiek słowo" • "do answer wstawiamy tylko nazwy plików, które zawierają • wszystkie szukane słowa" • bag asSet do: [ :document | • queryWords size = (bag occurrencesOf: document) • ifTrue: [answer add: document]]. • ^answer asSortedCollection asArray Przykład użycia: Index := WordIndex new. Index addDocument: 'pierwszy.txt'. Index addDocument: 'drugi.txt'. ..... oop := Index locateDocuments: #('klasa' 'obiekt' 'metoda'). oop do: [ :name | name out ].