Слияние, срезы и разбиение
Остались три задачи для персонала гардероба: собрать два гардероба в один, отдать часть вещей и развесить по крючкам вещи, которые принесли одной связкой.
Начнём со слияния. Если вещи висят на крючках с номерами, вещи второго гардероба вешают на следующие свободные крючки.
С именными бирками сложнее: что делать, если бирка 'color' есть в обоих гардеробах? У PHP на это два разных ответа:
<?php
$a = [1, 2];
$b = [3, 4];
echo json_encode(array_merge($a, $b)), "\n"; // [1,2,3,4]
echo json_encode([...$a, ...$b]), "\n"; // [1,2,3,4]
$defaults = ['color' => 'red', 'size' => 'M'];
$chosen = ['color' => 'blue'];
echo json_encode(array_merge($defaults, $chosen)), "\n"; // {"color":"blue","size":"M"}
echo json_encode($chosen + $defaults), "\n"; // {"color":"blue","size":"M"}
echo json_encode($defaults + $chosen), "\n"; // {"color":"red","size":"M"}Три способа слить массивы
array_merge
array_merge($a, $b) берёт элементы $a, а за ними элементы $b. Целые ключи она раздаёт заново по порядку, поэтому два списка склеиваются в один. При повторе строкового ключа побеждает правый массив: 'blue' из $chosen заменяет 'red' из $defaults.
Оператор +
$x + $y добавляет к левому массиву только те ключи, которых в нём ещё нет. Совпавший ключ остаётся за левым массивом, поэтому $defaults + $chosen сохраняет 'red'. Отсюда удобный приём: $chosen + $defaults — выбор пользователя, дополненный настройками по умолчанию.
Распаковка ...
Запись [...$a, ...$b] высыпает элементы обоих массивов в новый список, как array_merge. Со строковыми ключами она работает так же: с PHP 8.1 при повторе ключа побеждает правый массив.
Чем array_merge отличается от +, часто спрашивают на собеседовании. Ответ:
array_mergeнумерует целые ключи заново и отдаёт повторный строковый ключ правому массиву;+сохраняет все ключи левого массива и только добавляет недостающие.
Срез и вырезание
Срез — копия части массива. Его возвращает array_slice, а array_splice не копирует часть, а вырезает её:
$queue = ['ann', 'bob', 'cat', 'dan'];
$part = array_slice($queue, 1, 2);
echo implode(' ', $part), ' | ', count($queue), "\n"; // bob cat | 4
$cut = array_splice($queue, 1, 2);
echo implode(' ', $cut), ' | ', implode(' ', $queue), "\n"; // bob cat | ann dan
array_splice($queue, 1, 0, ['eve']);
echo implode(' ', $queue), "\n"; // ann eve danarray_slice копирует
array_slice($queue, 1, 2) возвращает новый массив: начать с позиции 1, считая с нуля, и взять 2 элемента. Третий аргумент — сколько взять, а не где закончить. Исходный массив не меняется: в $queue по-прежнему четыре имени.
array_splice вырезает
array_splice принимает массив по ссылке, как sort. Она вырезает кусок из самого $queue и возвращает вырезанное, а целые ключи оставшихся элементов нумерует заново.
Четвёртым аргументом можно передать, что вставить на освободившееся место. С длиной 0 она ничего не удаляет, а только вставляет: так 'eve' встала между 'ann' и 'dan'.
Здесь картинка с гардеробом неточна. Настоящий гардеробщик не может выдать вещь и при этом оставить её на крючке. А array_slice делает именно это: отдаёт копии, а вещи остаются на месте.
Из строки в массив и обратно
Строка с разделителями — та самая связка. explode развязывает её и развешивает куски по крючкам, а склеивает их обратно уже знакомая вам implode:
$csv = 'tea,milk,,bread';
$items = explode(',', $csv);
echo count($items), "\n"; // 4
var_dump($items[2]); // string(0) ""
echo implode(' + ', $items), "\n"; // tea + milk + + bread
echo implode(' ', str_split('abcdef', 2)), "\n"; // ab cd efДавайте разберём по строкам:
explode(',', $csv)режет строку по каждой запятой. Первым аргументом идёт разделитель, вторым — строка.- Между двумя запятыми подряд ничего нет, и
explodeвозвращает этот пустой кусок отдельным элементом. Поэтому частей четыре, а$items[2]— пустая строка. implodeсклеивает части обратно, и на месте пустого куска видны два пробела подряд.str_split('abcdef', 2)режет строку на куски по два байта; у латинских букв байт равен символу, поэтому здесь выходитab cd ef. Кириллическую букву она может разрезать пополам: для кириллицы естьmb_str_split.
Частая ошибка
Два списка сложили через +:
$week = ['mon', 'tue'];
$weekend = ['sat', 'sun'];
$days = $week + $weekend; // ✗
echo implode(' ', $days), "\n";Программа печатает mon tue, и PHP не выдаёт никаких сообщений. У обоих списков ключи 0 и 1, а + добавляет только ключи, которых слева нет: новых не оказалось. Исправление — array_merge($week, $weekend) или [...$week, ...$weekend]: оба дают mon tue sat sun.
Главное
array_mergeи[...$a, ...$b]дописывают элементы и нумеруют целые ключи заново; при повторе строкового ключа побеждает правый массив.+сохраняет все ключи левого массива и добавляет только недостающие, поэтому два списка через+не склеиваются.array_sliceвозвращает копию куска и не трогает источник, аarray_spliceвырезает кусок из самого массива и возвращает вырезанное.explodeрежет строку по разделителю и сохраняет пустые куски, аimplodeсклеивает массив обратно.