Macierze komórkowe i struktury

elementami macierzy są wartości tego samego typu (bool, int, double, char)

struktury danych heterogeniczne - pozwalające gromadzić elementy róznych typów:

struktura (struct) - wartości dostępne są w nazwanych polach

macierz komurkowa (cell array) - wartości zorganizowane są w macierzy, elementy dostępne są za pomocą indeksów liczbowych

Komórka - obiekt typu cell

# komórka (cell) zawierająca liczbę calkowitą 42
a = { 42 }
# komórka (cell) zawierająca znak 'A'
b = { 'A' }
# komórka z napisem
c = { 'Siała baba mak' }
whos a b c

a =
{
[1,1] = 42
}
b =
{
[1,1] = A
}
c =
{
[1,1] = Siała baba mak
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x1 8 cell
b 1x1 1 cell
c 1x1 15 cell
Total is 3 elements using 24 bytes

Wektory i macierze komórkowe

# wektor komórkowey wierszowy
c = { 42, 'A', 1:3:10, 'Witaj'}
whos c

c =
{
[1,1] = 42
[1,2] = A
[1,3] =
1 4 7 10
[1,4] = Witaj
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
c 1x4 38 cell
Total is 4 elements using 38 bytes

# wektor kolumnowy
c = { 42; 'A'; 1:3:10; 'Witaj'}
size(c)

c =
{
[1,1] = 42
[2,1] = A
[3,1] =
1 4 7 10
[4,1] = Witaj
}
ans =
4 1

# macierz komórkowa 2x2
c = { 42, 'A'; 1:3:10, 'Witaj'}
size(c)

c =
{
[1,1] = 42
[2,1] =
1 4 7 10
[1,2] = A
[2,2] = Witaj
}
ans =
2 2

# elementami macierzy komórkowej moga być macierze komórkowe
d = { c , c ; 1, 'A'}
whos d

d =
{
[1,1] =
{
[1,1] = 42
[2,1] =
1 4 7 10
[1,2] = A
[2,2] = Witaj
}
[2,1] = 1
[1,2] =
{
[1,1] = 42
[2,1] =
1 4 7 10
[1,2] = A
[2,2] = Witaj
}
[2,2] = A
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
d 2x2 85 cell
Total is 4 elements using 85 bytes

Alokacja pustej macierzy komórkowej

podobnie jak w przypadku zwykłych macierzy zalecane jest wczesniejsze zaalokowanie macierzy komórkowej (rozrzeczanie dynamiczen rozmiaru jest mniej efektywne)

funkcja cell(N, M) tworzy pustą macierz komórkową o wymiarach NxM

## pusta macierz - prealikacja macierzy komórkowej
x = cell(2, 3)
whos x

x =
{
[1,1] = [](0x0)
[2,1] = [](0x0)
[1,2] = [](0x0)
[2,2] = [](0x0)
[1,3] = [](0x0)
[2,3] = [](0x0)
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
x 2x3 0 cell
Total is 6 elements using 0 bytes

# ewentualnie można utworzyć macierz inicjując jej najdalszy element
y{2,3} = []

y =
{
[1,1] = [](0x0)
[2,1] = [](0x0)
[1,2] = [](0x0)
[2,2] = [](0x0)
[1,3] = [](0x0)
[2,3] = [](0x0)
}

Ćwiczenie: utwórz macierz komórkową o wymiarach 2×3 zawierającą 6 nastepujących elementów: * dzisiejsza data (zob. polecenie data) * tablica 2-elementowa zawierająca aktualną godzinę i minutę (zob. polecenie clock) * macierz jednostkowa o wymiarach 10×10 * napis “Witaj Świcie” * wektor wierszowy zawierający liczby calkowite od 1 do 100 * wektor 6 losowych liczb całkowitych z puli od 1 do 49 (wyniki losowanoa lotto) w kolejnosci rosnącej (zob. funkcję randi)

Indeksowanie elementów obiektu typu cell

nawiasy klamrowe {i, j} dają dostęp do wartości umieszczonych w komórkach

nawiasy okrągłe (i, j) dają dostęp do komórek (wynik jest obiektem typu cell)

x = { 42, 'A'; 1:3:10, 'Witaj'};
% indeksowanie wartości (1,1)
a = x{1,1}
% indeksowanie komórek
b = x(1,1)
whos a b

a = 42
b =
{
[1,1] = 42
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x1 8 double
b 1x1 8 cell
Total is 2 elements using 16 bytes

x = { 42, 'A'; 1:3:10, 'Witaj'};
% elementem {2,1} jest wektor
a = x{2,1}
% element 1 wektora z komórki x{2,1}
c = x{2, 1}(1)

a =
1 4 7 10
c = 1

% elementem (2,1) jest komórka zawierająca wektor
b = x(2, 1)
% element 1 wektora znajdującago się w pierwszej komórce znajdującej się w x(2,1)
d = x(2, 1){1}(1)
whos a b c d

b =
{
[1,1] =
1 4 7 10
}
d = 1
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x4 24 double
b 1x1 24 cell
c 1x1 8 double
d 1x1 8 double
Total is 7 elements using 64 bytes

Ineksowanie za pomoca dwukropka :

x = { 42, 'A', 1:3:10, 'Matlab'};
# pierwsze 3 elementy - 3 różne zmienne ans
x{1:3}

ans = 42
ans = A
ans =
1 4 7 10

% wynik można podstawić do 3 róznych zmiennych
[a b c] = x{1:3}
whos a b c

a = 42
b = A
c =
1 4 7 10
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x1 8 double
b 1x1 1 char
c 1x4 24 double
Total is 6 elements using 33 bytes

% wynikiem x(1:3) nowa macierz komórkowa
x(1:3)
% wynikiem jest jedna zmienna
a = x(1:3)
whos a x

ans =
{
[1,1] = 42
[1,2] = A
[1,3] =
1 4 7 10
}
a =
{
[1,1] = 42
[1,2] = A
[1,3] =
1 4 7 10
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x3 33 cell
x 1x4 39 cell
Total is 7 elements using 72 bytes

% indeksowanie podobne jak w macierzach
x = { 42, 'A'; 1:3:10, 'Matlab'};
% pierwsza kolumna
a = x(1, :)
% ostatni wiersz
b = x(end, :)

a =
{
[1,1] = 42
[1,2] = A
}
b =
{
[1,1] =
1 4 7 10
[1,2] = Matlab
}

Wyświetlanie zawartości komórek

celldisp() wypisuje zawartość kolejnych komórek

cellplot() wypisanie wartości w trybie graficznym (w oknie), brak w Octave

x = { 42, 'A'; 1:3:10, 'Matlab'};
disp(x)
celldisp(x)

{
[1,1] = 42
[2,1] =
1 4 7 10
[1,2] = A
[2,2] = Matlab
}
x{1,1} =
42
x{2,1} =
1 4 7 10
x{1,2} =
A
x{2,2} =
Matlab

% wyświetlanie rekurencyjne macierzy komórkowych zawierających inne macierze komórkowe
y = {1, 2, x}
celldisp(y)

y =
{
[1,1] = 1
[1,2] = 2
[1,3] =
{
[1,1] = 42
[2,1] =
1 4 7 10
[1,2] = A
[2,2] = Matlab
}
}
y{1} =
1
y{2} =
2
y{3}{1,1} =
42
y{3}{2,1} =
1 4 7 10
y{3}{1,2} =
A
y{3}{2,2} =
Matlab

% celplot() nie jest dostępne w Octave
cellplot(x)

warning: the 'cellplot' function is not yet implemented in Octave
Please read <https://www.octave.org/missing.html> to learn how you can
contribute missing functionality.
error: 'cellplot' undefined near line 2 column 1

Funkcje macierzowe

wiele funkcji i operacji macierzowych działa również na macierzach komórkowych (np. reshape, transpozycja)

iscell() spradza, czy zmienna jest typu cell

x = { 42, 'A'; 1:3:10, 'Matlab'};
% rozmiar
[w k] = size(x)
% transpozycja
y = x'

w = 2
k = 2
y =
{
[1,1] = 42
[2,1] = A
[1,2] =
1 4 7 10
[2,2] = Matlab
}

% zmiana kształtu
reshape(x, [1, 4])
% usuwanie elementów
x(1, :) = []

ans =
{
[1,1] = 42
[1,2] =
1 4 7 10
[1,3] = A
[1,4] = Matlab
}
x =
{
[1,1] =
1 4 7 10
[1,2] = Matlab
}

Macierz komórkowa z napisami

w obiekcie typu cell mozna przechowywać napisy o różnej długości

jest to wygodny sposób przechowywania zbioru napisow (np. kolejnych linii tekstu)

tekst = {'Ala ma kota', 'Siała baba mak', 'Matlab'}

tekst =
{
[1,1] = Ala ma kota
[1,2] = Siała baba mak
[1,3] = Matlab
}

Przydatne funkcje

cellstr() zamiana tablicy znakowej na znakową macierz komórkową. Wypełniające blanki zostają usunięte.

char() zamiana macierzy komórkowej na znakową

iscellstr() sprawdza, czy macierz jest macierzą komórkową z napisami

x = char('Ala', 'Ewa', 'Zenon')
% utowrzenie macierzy komorkowej znakowej (3 napisy)
y = cellstr(x)
whos x y

x =
Ala
Ewa
Zenon
y =
{
[1,1] = Ala
[2,1] = Ewa
[3,1] = Zenon
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
x 3x5 15 char
y 3x1 11 cell
Total is 18 elements using 26 bytes

disp(y{1}) % napis 'Ala'
a = length(y{1})
disp(x(1, :)) % napis 'Ala ' (2 spacje na koncu)
b = length(x(1, :))

Ala
a = 3
Ala
b = 5

tekst = {'Ala', 'Ewa', 'Zenon'};
% utworzenie macierzy znakowaej 3x5
x = char(tekst)
whos x

x =
Ala
Ewa
Zenon
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
x 3x5 15 char
Total is 15 elements using 15 bytes

tekst = {'raz', 'dwa', 'trzy', 'cztery'};
s = char(tekst);
whos tekst s
% czy macierz komórkowa znakowa ?
a = iscellstr(tekst)
b = iscellstr(s)
c = iscellstr({1 , 'A', 'Ala'})

Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
tekst 1x4 16 cell
s 4x6 24 char
Total is 28 elements using 40 bytes
a = 1
b = 0
c = 0

Ćwiczenie: utwórz tablicę komórkową zawierająca listę imion (np. Ala, Ewa, Janek), drugą zawierająca listę czasowników (np. lubi, je, czyta) i trzecia zawierającą rzeczowniki (np. kamienie, kotlety, koty). Napisz wyrażenie (lub funkcję), które tworzy zdania losując po jednym wyrazie z każdego zbioru (np. Ala lubi koty)

Struktury

struktyry posiadają nazwane pola, w których mozemy przechowywać zmienne dowolnego typu

struktura.pole dostęp do pól struktury uzyskujemy za pomocą kropki

możemy je tworzyć przypisując bezpośrednio wartość do pola

funkcja struct() pozwala tworzyć struktury. Argumentami funkcji są kolejne pary określające nazwę pola i wartość

struct(nazwa1, wartosc1, nazwa2, wartość2, ...)

# utowrzenie struktury za pomoca przypisania wartości
s1.liczba = 42
s1.nazwa = 'Matlab'
s1.macierz = rand([2,3])

s1 =
scalar structure containing the fields:
liczba = 42
s1 =
scalar structure containing the fields:
liczba = 42
nazwa = Matlab
s1 =
scalar structure containing the fields:
liczba = 42
nazwa = Matlab
macierz =
0.90546 0.84410 0.50294
0.29388 0.36011 0.69174

# utowrzenie struktury za pomoca funkcji struct()
s2 = struct('liczba', 42, 'nazwa', 'Matlab', 'macierz', rand([2,3]))
whos s1 s2 % ta struktura jest macierza 1x1

s2 =
scalar structure containing the fields:
liczba = 42
nazwa = Matlab
macierz =
0.241836 0.230792 0.186499
0.099092 0.119201 0.122511
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
s1 1x1 62 struct
s2 1x1 62 struct
Total is 2 elements using 124 bytes

Przydatne funkcje

rmfield(s, n) usuwa ze sruktury s pole o nazwie n

isstruct(s) spradza, czy s jest strukturą

isfield(s, n) sprawdza, czy pole o nazwie n znajduje się w strukturze s

fieldnames(s) zwraca listę (cell array) nazw pól

s = struct('liczba', 42, 'nazwa', 'Matlab', 'macierz', rand(5));
disp(s)
% nazwy pól struktury
nazwy = fieldnames(s)

scalar structure containing the fields:
liczba = 42
nazwa = Matlab
macierz =
0.038913 0.317290 0.831178 0.354825 0.522132
0.736033 0.781280 0.281603 0.907320 0.272378
0.244622 0.653326 0.608465 0.268054 0.593301
0.818070 0.741613 0.449265 0.981028 0.870832
0.224464 0.475633 0.370601 0.401830 0.257715
nazwy =
{
[1,1] = liczba
[2,1] = nazwa
[3,1] = macierz
}

% nie modyfikuje struktury ale zwraca kopię
rmfield(s, 'macierz')
% aktualna zawartość struktury
disp(s)

ans =
scalar structure containing the fields:
liczba = 42
nazwa = Matlab
scalar structure containing the fields:
liczba = 42
nazwa = Matlab
macierz =
0.038913 0.317290 0.831178 0.354825 0.522132
0.736033 0.781280 0.281603 0.907320 0.272378
0.244622 0.653326 0.608465 0.268054 0.593301
0.818070 0.741613 0.449265 0.981028 0.870832
0.224464 0.475633 0.370601 0.401830 0.257715

% podstawiamy wynik aby zachować zmiany
s = rmfield(s, 'macierz')
disp(s)

s =
scalar structure containing the fields:
liczba = 42
nazwa = Matlab
scalar structure containing the fields:
liczba = 42
nazwa = Matlab

% czy struktura zawiera pole o danej nazwie?
a = isfield(s, 'liczba')
b = isfield(s, 'xxx')

a = 1
b = 0

Do pól struktury możemy odnosić się również używając nazw pól w postaci łańcuchów znakowych

s = struct('liczba', 42, 'nazwa', 'Matlab', 'macierz', rand(5));
% pole o nazwie 'liczba'
a = s.('liczba')
t = 'nazwa'
% nazwa pola zawarta w zmiennej
b = s.(t)
n = fieldnames(s);
for i=1:length(n)
fprintf('\nPole o nazwie %s\n', n{i})
disp(s.(n{i}))
end

a = 42
t = nazwa
b = Matlab
Pole o nazwie liczba
42
Pole o nazwie nazwa
Matlab
Pole o nazwie macierz
0.912414 0.920362 0.263780 0.128573 0.340286
0.663009 0.914018 0.881667 0.286782 0.813027
0.648888 0.489993 0.766774 0.403041 0.284646
0.651711 0.414582 0.074597 0.489842 0.120202
0.136358 0.300551 0.394563 0.728933 0.287581

Wektory i macierze struktur

struktury moga byc elementami wektorów i macierzy (struct array)

tworzymy je odnosząc się do indeksów macierzy (tworzenie dynamiczne)

funkcja repmat pozwala utowrzyć macierz z kopiami struktury

sm(1).pole = 5
sm(2).pole = 42
whos sm

sm =
scalar structure containing the fields:
pole = 5
sm =
1x2 struct array containing the fields:
pole
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
sm 1x2 16 struct
Total is 2 elements using 16 bytes

# prealokacja macierzy strukrur przez zdefiniowanie ostatniego elementu
sa(10).pole = 3
whos sa
disp(sa)

sa =
1x10 struct array containing the fields:
pole
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
sa 1x10 8 struct
Total is 10 elements using 8 bytes
1x10 struct array containing the fields:
pole

% macierz 10x10 pustych elementów (tylko sb(10,10) jest strukturą z wartością pola 5 )
sb(10,10).pole = 5
whos sb
disp(sb)
sb(1,1)
sb(10,10)

sb =
10x10 struct array containing the fields:
pole
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
sb 10x10 8 struct
Total is 100 elements using 8 bytes
10x10 struct array containing the fields:
pole
ans =
scalar structure containing the fields:
pole = [](0x0)
ans =
scalar structure containing the fields:
pole = 5

% alokacja macierzy struktur za pomocą funkcji repmat
s3 = repmat(struct('pole', 42, 'nazwa', 'Matlab'), 2, 3)
whos s3
disp(s3)
a = s3(1, 2).pole
s3.pole
whos a

s3 =
2x3 struct array containing the fields:
pole
nazwa
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
s3 2x3 84 struct
Total is 6 elements using 84 bytes
2x3 struct array containing the fields:
pole
nazwa
a = 42
ans = 42
ans = 42
ans = 42
ans = 42
ans = 42
ans = 42
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x1 8 double
Total is 1 element using 8 bytes

Elementy pól wybranych struktur mogą być uzyte do utworzenia macierzy z tymi elementami

% umieszczenie wartości pól struktury w wektorze
a = [ s3.pole ]
whos a
size(a)

a =
42 42 42 42 42 42
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
a 1x6 48 double
Total is 6 elements using 48 bytes
ans =
1 6

Zagnieżdzone struktury

polami struktur moga być dowolne zmienne, w tym inne struktury

st = struct('pole1', struct('a', 13, 'b', 14), 'pole2', struct('x', -1))
disp(st)
% pole 1 jest strukturą
a = st.pole1
% struktura w polu1 ma pole 'a'
b = st.pole1.a

st =
scalar structure containing the fields:
pole1 =
scalar structure containing the fields:
a = 13
b = 14
pole2 =
scalar structure containing the fields:
x = -1
scalar structure containing the fields:
pole1 =
scalar structure containing the fields:
a = 13
b = 14
pole2 =
scalar structure containing the fields:
x = -1
a =
scalar structure containing the fields:
a = 13
b = 14
b = 13

Ćwiczenie zaprojektuj i utwórz strukturę, która będzie przechowywała dane dotyczące studenta, takie jak: imię, nazwisko, data urodzenia (data jest też strukturą zawierającą pola: dzień, miesiąc, rok), miejsce zamieszkania (adres zawiera pola: ulica, numer domu, kod pocztowy, kraj). Wprowadź przykładowe dane do struktury.

Utwórz macierz 100×100 zawierającą kopie tej struktury w każdym elemencie.

Zamiana struktury na macierz komórkową

cell2struct() zamiana macierzy komórkowej na strukturę

struct2cell() zamiana struktury na macierz komórkową

c = {'A', 1, 'Ala', [12,3]};
% utworzenie struktury z nazwami pól 'a', 'b', 'c', 'd'
d = cell2struct(c, {'a', 'b', 'c', 'd'}, 2)
disp(d)
whos c d

d =
scalar structure containing the fields:
a = A
b = 1
c = Ala
d =
12 3
scalar structure containing the fields:
a = A
b = 1
c = Ala
d =
12 3
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
c 1x4 28 cell
d 1x1 28 struct
Total is 5 elements using 56 bytes

% utworzenie macierzy komórkowej ze struktury
e = struct2cell(d)
disp(e)
whos e

e =
{
[1,1] = A
[2,1] = 1
[3,1] = Ala
[4,1] =
12 3
}
{
[1,1] = A
[2,1] = 1
[3,1] = Ala
[4,1] =
12 3
}
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
e 4x1 28 cell
Total is 4 elements using 28 bytes

Zadanie 8. Licz znaki

Stwórz plik o nazwie licz_znaki.m a w nim zdefiniuj funkcję o nazwe licz_znaki(), która dla podanego w argumencie napisu zwraca strukturę zawierającą nastepujące pola:

znaki zawiera ilość znaków w napisie

litery zawiera ilość liter (małych i duzych) w napisie

wyrazy zawiera ilość wyrazów w napisie (wyrazem jest dowolny ciąg znaków oddzielonych przynajmniej jedną spacją)

Argumentem funkcji może być napis lub tablica komórkowa z napisami. Jeżeli argumentem jest pojedynczy napis to wynikiem jest pojedyncza struktura. Jeżeli argumentem jest tablica komórkowa znakowa to wynikiem jest macierz struktur o takim samym wymiarze jak tablica komórkowa dana w argumencie. Każdy element macierzy wynikowej zlicza wówczas znaki odpowiadającego elementowi macierzy komórkowej (zobacz przykład niżej) W przypadku, gdy funkcja zostanie uruchomiona z argumentami innego typu lub w przypadku gdy uzytkonik poda niepoprawną ilość argumentów (różną od 1) to wypisywany jest stosowny komunikat błedu i program się kończy.

Przykład

Uruchomienie funkcji

x = licz_znaki('Ala ma kota')

zwróci strukturę zawierającą wartości:

x.znaki = 11
x.litery = 9
x.wyrazy = 3

Gdy argumentem będzie macierz komórkowa z napisami to wynikiem bedzie macierz struktur, np.:

a = { 'Ala ma kota', 'Matlab'};
x = licz_znaki(a)

utowrzy zmienną x, która jest macierzą 1×2

x(1,1).znaki = 11
x(1,1).litery = 9
x(1,1).wyrazy = 3
x(1,2).znaki = 6
x(1,2).litery = 6
x(1,2).wyrazy = 1