Tablice jako stosy, kolejki lub zbiory #1
Tablice często używane są jako stosy (LIFO – Last In First Out) lub kolejki (FIFO – First In First Out). PHP bardzo upraszcza nam to podejście do tablic dostarczając zestawu funkcji wyciągania i wkładania poszczególnych elementów ze stosów / kolejek.
Do tego czasem zachodzi potrzeba potraktować tablice jako zbiory danych. Tutaj też twórcy języka usprawniają nam pracę dostarczając odpowiednich metod.
Stosy
$stack = array(); array_push($stack, 'foo', 'bar', 'baz'); print_r($stack); $last_in = array_pop($stack); echo 'Last in:' . $last_in;
Array
(
[0] => foo
[1] => bar
[2] => baz
)
Last in:baz
Bajecznie proste array_push()
int array_push (array &$array, mixed $var [, mixed $...])
Funkcja ta traktuje tablicę $array jak stos i „wpycha” podane elementy na jej koniec. Tak naprawdę, daje to taki sam efekt jakbyśmy napisali:
$stack[] = 'foo'; $stack[] = 'bar'; $stack[] = 'baz';
Jeśli używasz array_push() do dodania do tablicy tylko jednego elementu – powinieneś zamiast niej użyć zwykłego operatora []. Co prawda array_push() umożliwia taką operację, jednak jest to nieopłacalne z perspektywy wydajności skryptu. Po prostu to samo można osiągnąć używając operatora [], a do tego podczas dodawania elementu nie jest wywoływana żadna funkcja.
array_pop()
mixed array_pop (&$array)
Ta funkcja z kolei zwraca ostatni element z tablicy oraz usuwa go z niej. Jeśli tablica jest pusta zostanie zwrócony NULL. Natomiast jeśli funkcja zostanie wywołana dla zmiennej nietablicowej, zostanie wygenerowane ostrzeżenie i także zwrócona wartość NULL.
Kolejki
Jeśli zdecydujemy się traktować tablice jak kolejki, możemy użyć funkcji array_unshift() do dodawania elementów na początku tablicy oraz array_shift() do ich usuwania z początku tablicy.$stack = array('qux', 'bar', 'baz'); $first_element = array_shift($stack); echo 'First: ' . $first_element; array_unshift($stack, 'foo', 'sally'); print_r($stack);
First: qux
Array
(
[0] => foo
[1] => sally
[2] => bar
[3] => baz
)
array_unshift()
int array_unshift (&$array, mixed $var [, mixed $...])
Funkcja ta dodaje element lub elementy na początku tablicy. Wszystkie klucze numeryczne są kasowane i elementy są numerowane od początku, zaczynając od zera. Klucze asocjacyjne nie są modyfikowane. Funkcja zwraca nową, aktualną ilość elementów w tablicy. Jeśli jako pierwszy argument nie przekażemy tablicy, array_unshift() wygeneruje ostrzeżenie i zwróci NULL.
array_shift()
mixed array_shift (array &$array)
Działanie tej funkcji jest analogiczne do array_pop() tylko że o ile tamta zwracała i usuwała ostatni element tablicy, o tyle ta zwraca i usuwa pierwszy element tablicy. Trzeba jeszcze dodać, że wszystkie klucze numeryczne będą skasowane i tablica będzie indeksowana od zera. Klucze asocjacyjne nie są ruszane.
array_pad()
Pisząc o operacjach przycinania tablicy to na początku, to na końcu, dodawania elementów itp. przypomniały mi się jeszcze dwie funkcje, które też niejako mogą przydać się w tego typu operacjach. Pierwszą z nich jest array_pad() czyli dopełnienie tablicy.array array_pad (array $input, int $pad_size, mixed $pad_value)
Funkcja ta jest bardzo prosta w użyciu i nieskomplikowana w działaniu. Najprościej mówiąc, dopełnia ona tablicę $input do rozmiaru zdefiniowanego przez $pad_size wartością $pad_value. Jeśli $pad_size jest dodatnie, wówczas tablica dopełniana jest do prawej, jeśli ujemne – do lewej. Natomiast jeśli wartość bezwzględna $pad_size jest mniejsza lub równa rozmiarowi tablicy $input nie zachodzi żadne dopełnianie.
Jak widać na powyższej definicji, funkcja array_pad() nie pracuje na oryginalnej tablicy, tylko na jej kopii, toteż wartością przez nią zwracaną jest dopełniona tablica. Jeśli natomiast podamy jej w pierwszym argumencie zmienną inną niż tablica, zostanie wygenerowane ostrzeżenie oraz zwrócona wartość NULL.
array_fill()
array array_fill(int $index, int $num, mixed $value)
Funkcja array_fill() jak widać nie wymaga od nas podania żadnej tablicy. Generuje ona natomiast tablicę na podstawie wytycznych, które jej podamy. Są to: indeks, od którego ma się zacząć numeracja elementów, czyli parametr $index. Następnie podajemy ilość elementów ($num) oraz wartość, jaką chcemy wypełnić tablicę. Działa to mniej więcej tak:
$b = array_fill(5, 10, 'sally'); print_r($b);
Array
(
[5] => sally
[6] => sally
[7] => sally
[8] => sally
[9] => sally
[10] => sally
[11] => sally
[12] => sally
[13] => sally
[14] => sally
)
Funkcja array_fill() wygeneruje błąd poziomu E_WARNING jeśli parametr określający ilość elementów ($num) jest mniejszy od zera.
Zbiory
Niektóre pehapowe funkcje zostały zaprojektowane specjalnie do operowania na tablicach traktując je jako zbiory danych. I tak na początek mamy funkcję array_diff(), która zwraca nam różnicę dwóch, lub więcej tablic.array_diff()
array array_diff(array $array1, array $array2 [, array $...])
Funkcja porównuje $array1 z $array2 i zwraca różnicę również w postaci tablicy. Możemy przekazać też więcej niż jedną tablicę do porównania, wówczas dostaniemy tablicę elementów niewystępujących w żadnej z podanych tablic.
$a = array(1,2,3,4,5,6,7,8,9,10); $b = array('foo' => 1, 'bar' => 3,5,6); $c = array(2,8,9); $wynik = array_diff($a,$b,$c); print_r($wynik);
Array
(
[3] => 4
[6] => 7
[9] => 10
)
Zauważmy, że funkcja ignoruje podczas porównywania klucze. Jeśli chcesz sprawdzać różnicę na zasadzie par array_diff_assoc()
array array_diff_assoc(array $array1, array $array2 [, array $...])
Działa na podobnej zasadzie co opisywana wyżej funkcja z tą różnicą, że ta bierze pod uwagę dodatkowo zgodność kluczy.
$a = array('foo' => 'bar', 'baz' => 'bar', 'bar', 'bar'); $b = array('bar'); $wynik = array_diff_assoc($a,$b); print_r($wynik);
Array
(
[foo] => bar
[baz] => bar
[1] => bar
)
array_diff_key
Funkcja ta, podobnie jak dwie powyższe, wylicza różnicę tablic i zwraca ją w postaci oddzielnej tablicy, jednak przy porównywaniu elementów, bierze ona pod uwagę nie wartości, a klucze.
array array_diff_key(array $array1, array $array2 [, array $ ...])
array_udiff()
Jeżeli ktoś myślał, że wymienione trzy funkcje to wszystko, co PHP nam dostarcza do wyliczania różnic między tablicami, to był w dużym błędzie. Poza tymi dwoma, powiedzmy, podstawowymi funkcjami, dostajemy jeszcze szereg innych funkcji umożliwiających nam definiowanie własnych sposobów porównywania elementów. Jedną z nich jest funkcja array_udiff().array array_udiff(array $array1, array $array2 [, array $...], callback $data_compare_func)
Kiedy jej używamy? W momencie, kiedy potrzebny jest nam bardziej złożony mechanizm porównywania tablic, niż ten, który dostarcza PHP. Jednym z takich przypadków będzie np. taki, kiedy musimy porównać ze sobą dwie tablice różniące się wymiarem. Rozważmy taki kod:
function compr($a, $b) { $aVal = is_array($a) ? $a['nazwisko'] : $a; $bVal = is_array($b) ? $b['nazwisko'] : $b; return strcmp($aVal, $bVal); } $aktorzy = array( array('imie' => 'Tom', 'nazwisko' => 'Cruise'), array('imie' => 'Jack', 'nazwisko' => 'Nicholson'), array('imie' => 'Brad', 'nazwisko' => 'Pitt') ); $nazwiska = array('Cruise', 'Pazura', 'Pitt'); $result = array_udiff($aktorzy, $nazwiska, 'compr'); print_r($result);
$aktorzy i jednowymiarową $nazwiska. Powiedzmy, że chcę z tablicy $aktorzy wybrać tylko te tablice, których element o kluczu ‘nazwisko’ nie pokrywa się z żadnym elementem tablicy $nazwiska. Wiadomo, że można pokombinować w „normalny” sposób – zagnieździć kilka pętli, dołożyć kilka if’ów i osiągniemy ten efekt. Pytanie tylko – po co? Powyższy kod robi dokładnie to, co opisałem, mianowicie wyświetli on:
Array
(
[1] => Array
(
[imie] => Jack
[nazwisko] => Nicholson
)
)
Dlaczego? A no dlatego, że tylko Nicholsona nie ma w tablicy $nazwiska. A teraz pytanie? Co mi się wyświetli, jeśli w wywołaniu array_udiff zamienię kolejnością porównywane tablice? Myślę, że jeśli zrozumiałeś na powyższym przykładzie o co chodzi w działaniu tej funkcji, już znasz odpowiedź, jeśli nie – sam sprawdź, ja nie powiem array_udiff_assoc
array array_udiff_assoc(array $array1, array $array2 [, array $...], callback $data_compare_func)
Ta funkcja działa bardzo podobnie do powyższej, z tą różnicą, że podczas porównanie bierze pod uwagę również zgodność kluczy porównywanych elementów.Posłużę się kodem z powyższego przykładu, tylko zamienię array_diff na array_diff_assoc.
function compr($a, $b) { $aVal = is_array($a) ? $a['nazwisko'] : $a; $bVal = is_array($b) ? $b['nazwisko'] : $b; return strcmp($aVal, $bVal); } $aktorzy = array( array('imie' => 'Tom', 'nazwisko' => 'Cruise'), array('imie' => 'Jack', 'nazwisko' => 'Nicholson'), array('imie' => 'Brad', 'nazwisko' => 'Pitt') ); $nazwiska = array('Cruise', 'Pazura', 'Pitt'); $result = array_udiff_assoc($aktorzy, $nazwiska, 'compr');
$nazwiska. Podobnie sprawa wygląda z Bradem Pittem. Jego indeks równy jest dwa zarówno w pierwszej jak i w drugiej tablicy. Zmodyfikujmy więc nieco tablicę $nazwiska:
function compr($a, $b) { $aVal = is_array($a) ? $a['nazwisko'] : $a; $bVal = is_array($b) ? $b['nazwisko'] : $b; return strcmp($aVal, $bVal); } $aktorzy = array( array('imie' => 'Tom', 'nazwisko' => 'Cruise'), array('imie' => 'Jack', 'nazwisko' => 'Nicholson'), array('imie' => 'Bradd', 'nazwisko' => 'Pitt') ); $nazwiska = array('Cruise', 'Pazura','trzeci' => 'Pitt'); $result = array_udiff_assoc($aktorzy, $nazwiska, 'compr');
Array
(
[1] => Array
(
[imie] => Jack
[nazwisko] => Nicholson
)
[2] => Array
(
[imie] => Bradd
[nazwisko] => Pitt
)
)
O ile, nazwisko ‘Pitt’ się zgadza zarówno w pierwszej jak i drugiej tablicy, o tyle klucze już są inne.
array_udiff_uassoc
array array_udiff_uassoc(array $array1, array $array2 [, array $ ...], callback $data_compare_function, callback $key_compare_function)
Funkcja ta działa na takiej samej zasadzie jak dwie poprzednie, z tą różnicą, że pozwala ona zdefiniować dwie oddzielne metody – jedną do porównywania wartości, drugą do kluczy. Myślę, że jeśli zrozumiałeś o co chodzi na dwóch poprzednich przykładach, to nie potrzeba się zagłębiać w jej działanie array_diff_ukey
array array_diff_ukey(array $array1, array $array2 [, array $ ... ], callback $key_compare_func)
Po raz kolejny, bardzo podobna w działaniu funkcja co wcześniej opisane. array_diff_ukey przy porównaniu bierze pod uwagę tylko klucze, a samo porównanie wykonywane jest za pomocą funkcji dostarczonej przez użytkownika.
array_diff_uassoc
array array_diff_uassoc(array $array1, array $array2 [, array $ ... ], callback $key_compare_func)
Ostatnia funkcja z rodziny wyliczających różnicę zbiorów Na tym kończę ten wpis, jednak nie kończę jeszcze tematu zbiorów. Omówiłem funkcje obliczające różnicę, a co z częścią wspólną?
Konstrukcje jezykowe Tablice jako stosty, kolejki lub zbiory #2