MidТеория4 min

Функции массивов

array_map, array_filter, array_reduce, array_merge vs +, spread

Трансформация: array_map

<?php
declare(strict_types=1);

$numbers = [1, 2, 3, 4, 5];

// Transform each element
$doubled = array_map(fn(int $n): int => $n * 2, $numbers);
// [2, 4, 6, 8, 10]

// Keys are PRESERVED
$arr = [10 => 'a', 20 => 'b', 30 => 'c'];
$upper = array_map('strtoupper', $arr);
// [10 => 'A', 20 => 'B', 30 => 'C']

// Multiple arrays (zip)
$keys = ['name', 'age', 'city'];
$values = ['Alice', 25, 'Moscow'];
$result = array_map(null, $keys, $values);
// [['name', 'Alice'], ['age', 25], ['city', 'Moscow']]

// With null callback — creates array of arrays
$a = [1, 2, 3];
$b = ['a', 'b', 'c'];
$zipped = array_map(null, $a, $b);
// [[1, 'a'], [2, 'b'], [3, 'c']]

Запомни: array_map() сохраняет ключи исходного массива. Callback получает только ЗНАЧЕНИЯ (не ключи). Для доступа к ключам используйте array_map с array_keys или array_walk.

Фильтрация: array_filter

<?php
declare(strict_types=1);

$numbers = [0, 1, 2, '', null, false, 3, '0'];

// Without callback — removes falsy values
$filtered = array_filter($numbers);
// [1 => 1, 2 => 2, 6 => 3] — keys preserved!

// With callback
$even = array_filter([1, 2, 3, 4, 5], fn(int $n): bool => $n % 2 === 0);
// [1 => 2, 3 => 4] — keys preserved!

// Reindex after filtering
$even = array_values(array_filter([1, 2, 3, 4, 5], fn(int $n): bool => $n % 2 === 0));
// [0 => 2, 1 => 4]

// Filter by keys (ARRAY_FILTER_USE_KEY)
$data = ['name' => 'Alice', 'age' => 25, '_internal' => true];
$public = array_filter(
    $data,
    fn(string $key): bool => !str_starts_with($key, '_'),
    ARRAY_FILTER_USE_KEY
);
// ['name' => 'Alice', 'age' => 25]

// Filter by key AND value (ARRAY_FILTER_USE_BOTH)
$filtered = array_filter(
    $data,
    fn(mixed $value, string $key): bool => $key !== '_internal' && $value !== null,
    ARRAY_FILTER_USE_BOTH
);

Ловушка экзамена: array_filter() без callback удаляет ВСЕ falsy-значения: 0, '', null, false, '0', []. При этом ключи СОХРАНЯЮТСЯ (массив не переиндексируется). '0' является falsy и тоже будет удалена!

Сведение: array_reduce

<?php
declare(strict_types=1);

$numbers = [1, 2, 3, 4, 5];

// Sum
$sum = array_reduce($numbers, fn(int $carry, int $item): int => $carry + $item, 0);
echo $sum;  // 15

// Product
$product = array_reduce($numbers, fn(int $carry, int $item): int => $carry * $item, 1);
echo $product;  // 120

// Building a string
$words = ['Hello', 'World', 'PHP'];
$sentence = array_reduce(
    $words,
    fn(string $carry, string $word): string => $carry === '' ? $word : "$carry $word",
    ''
);
echo $sentence;  // Hello World PHP

// Flattening nested arrays
$nested = [[1, 2], [3, 4], [5, 6]];
$flat = array_reduce($nested, fn(array $carry, array $item): array => [...$carry, ...$item], []);
// [1, 2, 3, 4, 5, 6]

array_walk

<?php
declare(strict_types=1);

// array_walk modifies array IN PLACE
$prices = ['apple' => 1.20, 'banana' => 0.50, 'cherry' => 2.00];

array_walk($prices, function (float &$price, string $name): void {
    $price = round($price * 1.1, 2);  // Increase by 10%
});
// $prices = ['apple' => 1.32, 'banana' => 0.55, 'cherry' => 2.2]

// With extra data
array_walk($prices, function (float &$price, string $name, float $tax): void {
    $price = round($price * (1 + $tax), 2);
}, 0.2);  // 20% tax

// Recursive version
$tree = [
    'a' => [1, 2, 3],
    'b' => [4, 5, 6],
    'c' => 7,
];
array_walk_recursive($tree, function (int &$value): void {
    $value *= 2;
});
// ['a' => [2, 4, 6], 'b' => [8, 10, 12], 'c' => 14]

Запомни: array_map() возвращает НОВЫЙ массив. array_walk() модифицирует массив НА МЕСТЕ (in-place). array_walk получает ключи в callback, array_map — нет.

Объединение массивов

array_merge vs оператор +

<?php
declare(strict_types=1);

// array_merge — reindexes numeric keys, later values overwrite string keys
$a = ['x' => 1, 'y' => 2, 0 => 'a'];
$b = ['x' => 3, 'z' => 4, 0 => 'b'];

$merged = array_merge($a, $b);
// ['x' => 3, 'y' => 2, 0 => 'a', 1 => 'b', 'z' => 4]
// Numeric keys REINDEXED, string 'x' overwritten by $b

// + operator — keeps FIRST occurrence, preserves all keys
$union = $a + $b;
// ['x' => 1, 'y' => 2, 0 => 'a', 'z' => 4]
// 'x' stays from $a, 0 stays from $a, 'z' added from $b

$c = [0 => 'zero-a', 1 => 'one-a'];
$d = [0 => 'zero-b', 1 => 'one-b', 2 => 'two-b'];
$union = $c + $d;
// [0 => 'zero-a', 1 => 'one-a', 2 => 'two-b']
// Existing keys NOT overwritten!

Ловушка экзамена:

  • array_merge(): числовые ключи переиндексируются, строковые ключи — последний побеждает
  • + (union): ключи НЕ переиндексируются, ПЕРВЫЙ побеждает (существующие ключи не перезаписываются) Это ОЧЕНЬ частый вопрос сертификации!

Spread оператор vs array_merge

<?php
declare(strict_types=1);

$a = [1, 2, 3];
$b = [4, 5, 6];

// Both reindex numeric keys
$merged1 = array_merge($a, $b);   // [1, 2, 3, 4, 5, 6]
$merged2 = [...$a, ...$b];        // [1, 2, 3, 4, 5, 6]

// With string keys (PHP 8.1+)
$defaults = ['color' => 'red', 'size' => 'M'];
$custom = ['size' => 'L', 'weight' => 100];
$config = [...$defaults, ...$custom];
// ['color' => 'red', 'size' => 'L', 'weight' => 100]

array_merge_recursive

<?php
declare(strict_types=1);

$a = ['color' => 'red', 'sizes' => ['S', 'M']];
$b = ['color' => 'blue', 'sizes' => ['L', 'XL']];

$result = array_merge_recursive($a, $b);
// [
//     'color' => ['red', 'blue'],     — values merged into array!
//     'sizes' => ['S', 'M', 'L', 'XL'] — arrays merged
// ]

// Compare with array_merge:
$result = array_merge($a, $b);
// ['color' => 'blue', 'sizes' => ['L', 'XL']]
// Last value wins for string keys

Извлечение и проверка

<?php
declare(strict_types=1);

$user = ['name' => 'Alice', 'age' => 25, 'city' => 'Moscow'];

// Keys and values
$keys = array_keys($user);     // ['name', 'age', 'city']
$values = array_values($user);  // ['Alice', 25, 'Moscow']

// Combine arrays
$combined = array_combine(['a', 'b', 'c'], [1, 2, 3]);
// ['a' => 1, 'b' => 2, 'c' => 3]

// Flip keys and values
$flipped = array_flip(['a' => 1, 'b' => 2, 'c' => 3]);
// [1 => 'a', 2 => 'b', 3 => 'c']

// Unique values
$unique = array_unique([1, 2, 2, 3, 3, 3]);
// [0 => 1, 1 => 2, 3 => 3] — keys preserved!

// Count values
$counts = array_count_values(['a', 'b', 'a', 'c', 'b', 'a']);
// ['a' => 3, 'b' => 2, 'c' => 1]

// Slice
$slice = array_slice($values, 1, 2);     // [25, 'Moscow']
$slice = array_slice($values, 1, 2, true); // [1 => 25, 2 => 'Moscow'] (preserve keys)

// Column from multidimensional array
$users = [
    ['name' => 'Alice', 'age' => 25],
    ['name' => 'Bob', 'age' => 30],
];
$names = array_column($users, 'name');        // ['Alice', 'Bob']
$indexed = array_column($users, null, 'name'); // Indexed by name

Разница массивов

<?php
declare(strict_types=1);

$a = [1, 2, 3, 4, 5];
$b = [3, 4, 5, 6, 7];

// array_diff — values in $a not in $b
$diff = array_diff($a, $b);       // [0 => 1, 1 => 2]

// array_intersect — values in both
$inter = array_intersect($a, $b); // [2 => 3, 3 => 4, 4 => 5]

// Key-based versions
$x = ['a' => 1, 'b' => 2, 'c' => 3];
$y = ['a' => 1, 'b' => 5, 'd' => 3];

$diffKey = array_diff_key($x, $y);    // ['c' => 3]
$diffAssoc = array_diff_assoc($x, $y); // ['b' => 2, 'c' => 3]
$interKey = array_intersect_key($x, $y); // ['a' => 1, 'b' => 2]

Вопросы с экзамена ZCE

Проверь себя

5 из 122

Что выведет следующий код? ```php $m = [7, 2, 10, 4, 3, 8, 12, 11, 5, 13]; $filtered = array_filter($m, fn($v) => $v >= 5 && $v <= 10); sort($filtered); echo implode(',', $filtered); ```

Что выведет следующий код? ```php $result = (function($arr) { return array_sum($arr); })([1, 2, 3, 4]); echo $result; ```

Что выведет следующий код? ```php $a = array(1,2,3); $b = array(7,8,9); $counta = count($a); $countb = sizeof($b); if ($counta===$countb) { echo "They are equal and have the same type"; } else { echo "They are not equal or they are not of the same type"; } ```

Что выведет следующий код? ```php $a = [1 => 'a', 2 => 'b', 3 => 'c']; $b = [3 => 'c', 4 => 'd', 5 => 'e']; echo count(array_intersect_assoc($a, $b)); ```

Что выведет следующий код? ```php $a = [1, 2, 3, 4, 5]; $b = array_slice($a, 2); $c = array_splice($a, 2); echo count($a) . "-" . count($b) . "-" . count($c); ```

Code Challenges

Переворот массива

Напишите функцию, которая переворачивает массив без использования array_reverse().

Test Cases

1. Input: [1,2,3,4,5]→ Expected: [5,4,3,2,1]
2. Input: ["a","b","c"]→ Expected: ["c","b","a"]
3. Input: []→ Expected: []

Разбиение массива на части

Напишите функцию, которая разбивает массив на части заданного размера без использования array_chunk().

Test Cases

1. Input: [1,2,3,4,5], size=2→ Expected: [[1,2],[3,4],[5]]
2. Input: [1,2,3], size=1→ Expected: [[1],[2],[3]]
3. Input: [1,2,3,4], size=4→ Expected: [[1,2,3,4]]
4. Input: [], size=3→ Expected: []

Выравнивание вложенного массива

Напишите функцию, которая рекурсивно разглаживает вложенные массивы в один плоский массив.

Test Cases

1. Input: [1,[2,[3,4],5],6]→ Expected: [1,2,3,4,5,6]
2. Input: [[1,2],[3,[4]]]→ Expected: [1,2,3,4]
3. Input: [1,2,3]→ Expected: [1,2,3]
4. Input: []→ Expected: []

Транспонирование матрицы

Напишите функцию, которая транспонирует двумерную матрицу (строки становятся столбцами).

Test Cases

1. Input: [[1,2,3],[4,5,6]]→ Expected: [[1,4],[2,5],[3,6]]
2. Input: [[1,2],[3,4],[5,6]]→ Expected: [[1,3,5],[2,4,6]]
3. Input: [[1]]→ Expected: [[1]]