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ę.