W tym epizodzie pochylamy się nad tablicami i różnymi funkcjami tablicowymi, które powinniśmy poznać. Nauczymy się m. in. zagadnień takich jak:
- wyciąganie losowych elementów z tablicy bądź jej losowe tasowanie
- łączenie tablic w jedną
- zamiana kluczy z wartościami w tablicach asocjacyjnych
- zamiana tablicy na napis i odwrotnie
- niezwykle przydatna funkcja array_column
Wykonamy też sporą dawkę ćwiczeń utrwalających.
Do dzieła.
Losowość – array_rand, shuffle
Aby otrzymać losowy indeks danej tablicy używamy funkcji array_rand. Przyjmuje ona tablicę i zwraca losowy indeks tej tablicy, którego możemy użyć:
<?php
$foods = ['cake', 'bar', 'apple'];
$random_idx = array_rand($foods);
$random_food = $foods[$random_idx];
echo $random_food;
//apple
Jak widać array_rand jest bardzo prosta i nie zwraca losowego elementu, ale jego indeks.
Inną funkcją jest shuffle. Ona dokonuje losowego pomieszania wartości w naszej tablicy.
<?php
$foods = ['cake', 'bar', 'apple'];
shuffle($foods);
var_dump($foods);
// array(3) { [0]=> string(5) "apple" [1]=> string(3) "bar" [2]=> string(4) "cake" }
?>
Łączenie tablic – array_merge, array_combine
Funkcja array_merge pozwala nam łączyć wiele tablic w jedną wielką tablicę.
<?php
$foods = ['cake', 'bar', 'apple'];
$drinks = ['coffee', 'tea', 'juice'];
$menu = array_merge($foods, $drinks);
print_r($menu);
//Array ( [0] => cake [1] => bar [2] => apple [3] => coffee [4] => tea [5] => juice )
Funkcja array_combine pozwala nam natomiast na utworzenie tablicy asocjacyjnej z dwóch tablic-list, z których pierwsza reprezentuje klucze zaś druga wartości:
<?php
$keys = ["name", "age"];
$values = ["John", 30];
$person = array_combine($keys, $values);
echo $person['name'] . "</br>";
echo $person['age'] . "</br>";
// John
// 30
print_r($person);
//Array ( [name] => John [age] => 30 )
Tablice asocjacyjne – array_flip, array_fill_keys
Funkcja array_fill_keys pozwala nam stworzyć taki prototyp jakiejś tablicy asocjacyjnej. Chcemy na przykład, aby miała ona klucze „imię”, „wiek” oraz „e-mail”, zaś wartości domyślnie na „nieznane”.
Tak oto tworzymy taką tablicę asocjacyjną:
<?php
$keys = ["name", "age", 'email'];
$unknown_person = array_fill_keys($keys, 'unknown');
print_r($unknown_person);
//Array ( [name] => unknown [age] => unknown [email] => unknown )
Funkcja array_flip pozwala nam – z jakiegokolwiek powodu – zamienić klucze z wartościami w tablicy asocjacyjnej:
<?php
$person = [
'name' => 'John',
'age' => 30
];
$flipped = array_flip($person);
print_r($person);
// Array ( [name] => John [age] => 30 )
print_r($flipped);
// Array ( [John] => name [30] => age )
Tablica do napisu i odwrotnie – implode, explode
Funkcja implode pozwala nam zamienić tablicę na napis, połączony danym separatorem. Oto przykład:
<?php
$foods = ['cake', 'bar', 'apple'];
echo implode(", ", $foods);
// cake, bar, apple
Z tablicy otrzymujemy jeden element, jakim jest napis, gdzie wszystkie elementy tablicy zostały do siebie doklejone, używając separatora, w tym wypadku – przecinka ze spacją.
Działaniem odwrotnym jest explode, które bierze napis i „tnie” go po podanym separatorze, zwracając tablicę zawierającą elementy z pociętego napisu. Przykład z manuala PHP:
<?php
$pizza = "piece1 piece2 piece3 piece4 piece5 piece6";
$pieces = explode(" ", $pizza);
print_r($pieces);
// Array ( [0] => piece1 [1] => piece2 [2] => piece3 [3] => piece4 [4] => piece5 [5] => piece6 )
Tutaj mamy napis i „tniemy” po spacji, zwracając listę elementów (napisów). Spacje zostają wycięte zaś nasze elementy lądują w tablicy pod odpowiednimi indeksami.
Tablice w tablicy – array_column
Nie wiem, czy o tym wspominaliśmy, chyba nie, ale tablica może zawierać inne tablice jako swoje elementy. Mało tego – tablica-lista może być listą tablic asocjacyjnych jak w przykładzie poniżej i jest to bardzo częsta sytuacja:
<?php
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
)
);
Możemy po takiej tablicy przejść i np. wypisać sobie imię danego rekordu:
<?php
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
)
);
foreach($records as $record){
echo $record['first_name'] . "</br>";
}
// John
// Sally
// Jane
// Peter
Co jednak, gdybyśmy chcieli z tej listy tablic asocjacyjnych wyciągnąć listę wszystkich imion?
Pomoże nam w tym array_column:
<?php
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
)
);
$first_names = array_column($records, 'first_name');
print_r($first_names);
//Array ( [0] => John [1] => Sally [2] => Jane [3] => Peter )
Zadanie 1 – średnia ocen uczniów
Mamy taką oto listę uczniów:
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
'grade' => 5
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
'grade' => 4
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
'grade' => 3
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
'grade' => 4
)
);
Chcemy napisać funkcję, która będzie umiała wyliczyć średnią ocen uczniów, operując na rekordach w takiej postaci.
Do dzieła.
<?php
$records = array(
array(
'id' => 2135,
'first_name' => 'John',
'last_name' => 'Doe',
'grade' => 5
),
array(
'id' => 3245,
'first_name' => 'Sally',
'last_name' => 'Smith',
'grade' => 4
),
array(
'id' => 5342,
'first_name' => 'Jane',
'last_name' => 'Jones',
'grade' => 3
),
array(
'id' => 5623,
'first_name' => 'Peter',
'last_name' => 'Doe',
'grade' => 4
)
);
function average_grade($students){
$grades = array_column($students, 'grade');
return array_sum($grades) / count($grades);
}
echo average_grade($records);
//4
Przyjmujemy listę tablic asocjacyjnych students. Za pomocą array_column wyłuskujemy listę ocen.
Zwracamy sumę ocen (funkcja array_sum) podzieloną przez ilość ocen (funkcja count).
Zadanie 2 – własna funkcja array_rand
Funkcja array_rand zwraca losowy indeks danej tablicy. Przypomnijmy sobie, jak ona działa
<?php
$foods = ['cake', 'bar', 'apple'];
$random_idx = array_rand($foods);
$random_food = $foods[$random_idx];
echo $random_food;
//apple
Napiszmy coś podobnego.
<?php
$foods = ['cake', 'bar', 'apple'];
function rand_idx($arr){
return random_int(0, count($arr) - 1);
}
$random_idx = rand_idx($foods);
$random_food = $foods[$random_idx];
echo $random_food;
//bar
Nasza funkcja przyjmuje tablicę i zwraca losową liczbę z zakresu od 0 do długości tej tablicy – 1 (jako że indeksy są liczone od 0, ostatni indeks to będzie właśnie długość tablicy minus 1).
Proste.
Zadanie 3 – wybierz losowy element
Funkcja, której nie ma, a przydałaby się. Bierzemy tablicę i zwracamy jej losowy element, nie indeks tego elementu.
Do dzieła.
<?php
$foods = ['cake', 'bar', 'apple'];
function rand_el($arr){
$rand_idx = array_rand($arr);
return $arr[$rand_idx];
}
echo rand_el($foods);
//apple
Przyjmujemy tablicę, losujemy jej jakiś losowy indeks, zwracamy element tej tablicy znajdujący się pod tym wylosowanym indeksem.
Proste.
Zadanie 4 – prosty, własny array_merge
Przypomnijmy sobie, jak działa array_merge:
<?php
$foods = ['cake', 'bar', 'apple'];
$drinks = ['coffee', 'tea', 'juice'];
$menu = array_merge($foods, $drinks);
print_r($menu);
//Array ( [0] => cake [1] => bar [2] => apple [3] => coffee [4] => tea [5] => juice )
Dwie tablice zostają połączone ze sobą. Postarajmy się napisać własną funkcję, która na to pozwala.
<?php
$foods = ['cake', 'bar', 'apple'];
$drinks = ['coffee', 'tea', 'juice'];
function simple_merge($arr1, $arr2) {
return [...$arr1, ...$arr2];
}
$menu = simple_merge($foods, $drinks);
print_r($menu);
//Array ( [0] => cake [1] => bar [2] => apple [3] => coffee [4] => tea [5] => juice )
Przyjmujemy dwie tablice i zwracamy jedną. Używamy tutaj dotąd nieznanego operatora rozpakowania „…”. Wygląda identycznie jak inny operator, pozwalający funkcji przyjmować dowolną ilość argumentów, ale tutaj te trzy kropki oznaczają „wypakowanie” elementów tablicy.
I to się dzieje. Zwracana jest 1 tablica, do której „wypakowano” elementy z tablicy 1 i 2.
Zadanie 5 – własny array_fill_keys
Przypomnijmy sobie, jak działa array_fill_keys:
<?php
$keys = ["name", "age", 'email'];
$unknown_person = array_fill_keys($keys, 'unknown');
print_r($unknown_person);
//Array ( [name] => unknown [age] => unknown [email] => unknown )
Funkcja przyjmuje tablicę zawierającą klucze oraz domyślną wartość i zwraca tablicę asocjacyjną z tymi kluczami i domyślną wartością.
Postarajmy się to odtworzyć:
<?php
$keys = ["name", "age", 'email'];
function my_fill_keys($keys_arr, $value){
$output = array();
foreach($keys_arr as $key){
$output[$key] = $value;
}
return $output;
}
$unknown_person = my_fill_keys($keys, 'unknown');
print_r($unknown_person);
//Array ( [name] => unknown [age] => unknown [email] => unknown )
Nasza funkcja przyjmuje klucze oraz domyślną wartość. Tworzy pustą tablicę output.
Przechodzimy w pętli po kluczach i w naszej tablicy output pod takim kluczem zapisujemy domyślną wartość.
Zwracamy output, funkcja działa jak array_fill_keys.
Myślę, że na razie wystarczy tych zabaw z tablicami. Poznaliśmy naprawdę dużo i jest to dobre miejsce, aby zrobić sobie przerwę.