Скачиваний:
18
Добавлен:
02.05.2014
Размер:
906.24 Кб
Скачать

Операции над массивами

Существует довольно много операций, которые можно выполнять с массивами (в дополнение к общим операциям над переменными). Давайте перечислим их, а заодно и подытожим все сказанное выше.

Доступ по ключу

Как мы уже знаем, ассоциативные массивы – объекты, которые наиболее приспособлены для выборки из них данных путем указания нужного ключа. В PHP и для всех массивов, и для списков (которые, еще раз напомню, также являются массивами) используется один и тот же синтаксис, что является очень большим достоинством. Вот как это выглядит:

echo $Arr["anykey"]; // выводит элемент массива $Arr с ключом anykey

echo $Arr["first"]["second"]; // так используются двумерные массивы

echo (SomeFuncThatReturnsArray())[5]; // ОШИБКА! Так нельзя!

// Вот так правильно:

$Arr= SomeFuncThatReturnsArray();

echo $Arr[5];

Последний пример показывает, что PHP сильно отличается от Си с точки зрения работы с массивами: в нем нет такого понятия, как "контекст массива", а значит, мы не можем применить [] непосредственно к значению, возвращенному функцией. Величина $Arr[ключ] является полноценным "левым значением", т. е. может стоять в левой части оператора присваивания, от нее можно брать ссылку с помощью оператора &, и т. д. Например:

$Arr["anykey"]=array(100,200); // присваиваем элементу массива 100

$ref=&$Arr["first"]["second"]; // $ref — синоним элемента массива

$Arr[]="for add"; // добавляем новый элемент

Функция count()

Мы можем определить размер (число элементов) в массиве при помощи стандартной функции count():

$num=count($Names); // теперь в $num — число элементов в массиве

Сразу отмечу, что count() работает не только с массивами, но и с объектами и даже с обычными переменными (для последних count() всегда равен 1, как будто переменная – это массив с одним элементом). Впрочем, ее очень редко применяют для чего-либо, отличного от массива – разве что по-ошибке.

Слияние массивов

Еще одна фундаментальная операция – слияние массивов, т. е. создание массива, содержащего как элементы одного, так и другого массива. Реализуется это при помощи оператора +. Например:

$a=array("a"=>"aa", "b"=>"bb");

$b=array("c"=>"cc", "d"=>"dd");

$c=$a+$b;

В результате в $c окажется ассоциативный массив, содержащий все 4 элемента, а именно: array("a"=>"aa", "b"=>"bb", "c"=>"cc", "d"=>"dd"), причем именно в указанном порядке. Если бы мы написали $c=$b+$a, результат бы был немного другой, а именно: array("c"=>"cc", "d"=>"dd", "a"=>"aa", "b"=>"bb"), т. е. элементы расположены в другом порядке. Видите, как проявляется направленность массивов? Она заставляет оператор + стать некоммутативным, т. е. $a+$b не равно $b+$a, если $a и $b – массивы.

Будьте особенно внимательны при слиянии таким образом списков. Рассмотрим следующие операторы:

$a=array(10,20,30);

$b=array(100,200);

$c=$a+$b;

Возможно, вы рассчитываете, что в $c будет array(10,20,30,100,200)? Это неверно: там окажется array(10,20,30). Вот почему так происходит. При конкатенации массивов с некоторыми одинаковыми элементами (то есть, элементами с одинаковыми ключами) в результирующем массиве останется только один элемент с таким же ключом – тот, который был в первом массиве, и на том же самом месте. Последний факт может слегка озадачить. Казалось бы, элементы массива $b по логике должны заменить элементы из $a. Однако все происходит наоборот. Окончательно выбивает из колеи следующий пример:

$a=array('a'=>10, 'b'=>20);

$b=array('c'=>30, 'b'=>'new?');

$a+=$b;

Мы-то ожидали, что оператор += обновит элементы $a при помощи элементов $b. А напрасно. В результате этих операций значение $a не изменится. Так как же нам все-таки обновить элементы в массиве $a? Получается, только прямым способом – с помощью цикла:

foreach ($b as $k=>$v) $a[$k]=$v;

Что поделать, так уж распорядились разработчики PHP. В массиве никогда не может быть двух элементов с одинаковыми ключами, потому что все операции, применимые к массивам, всегда контролируют, чтобы этого не произошло. Впрочем, на мой взгляд, данное свойство вовсе не достоинство, а недостаток – вполне можно было бы позволить оператору + оставлять одинаковые ключи, а всем остальным – запретить это делать. Что ж, разработчики PHP "пошли другим путем"...

Так как списки являются тоже ассоциативными массивами, оператор + будет работать с ними неправильно! Например, в результате слияния списков array(10,20) и array(100,200,300) получится список array(10,20,300) – всего из трех элементов!

Косвенный перебор элементов массива

Довольно часто при программировании на PHP нам приходится перебирать все без исключения элементы некоторого массива. Если наш массив – список, то эта задача, как мы уже знаем, не будет особенно обременительной:

// Пусть $Names – список имен. Распечатаем их в столбик

for($i=0; $i<count($Names); $i++)

echo $Names[$i]."\n";

Я стараюсь везде, где можно, избегать помещения имени переменной-массива в кавычки – например, предыдущий пример я не пишу вот так:

for($i=0; $i<count($Names); $i++)

echo "$Names[$i]\n";

Дело в том, что это, пожалуй, единственный способ, который совместим с PHP версии 3. А что касается четвертой версии, то мы спокойно можем помещать массивы в строки, заключив их в фигурные скобки вместе с символом $:

$Names=array(

array(’name’=>’Вася’, ’age’=>20),

array(’name’=>’Билл’, ’age’=>40)

);

for($i=0; $i<count($Names); $i++)

echo "{$Names[$i][’age’]}\n";

Давайте теперь предположим, что массив $Names ассоциативный: его ключи – имена людей, а значения, сопоставленные ключам – например, возраст этих людей. Для перебора такого массива можно воспользоваться конструкцией наподобие следующей:

for(Reset($Names); ($k=key($Names)); Next($Names))

echo "Возраст $k – { $Names[$k]} лет\n";

Эта конструкция опирается на еще одно свойство ассоциативных массивов в PHP. А именно, мало того, что массивы являются направленными, в них есть еще и такое понятие, как текущий элемент. Функция Reset() просто устанавливает этот элемент на первую позицию в массиве. Функция key() возвращает ключ, который имеет текущий элемент (если он указывает на конец массива, возвращается пустая строка, что позволяет использовать вызов key() в контексте второго выражения for). Ну а функция Next() просто перемещает текущий элемент на одну позицию вперед. На самом деле, две простейшие функции, – Reset() и Next(), – помимо выполнения своей основной задачи, еще и возвращают некоторые значения, а именно:

●функция Reset() возвращает значение первого элемента массива (или пустую строку, если массив пуст);

●функция Next() возвращает значение элемента, следующего за текущим (или пустую строку, если такого элемента нет).

Иногда (кстати, гораздо реже) бывает нужно перебрать массив с конца, а не с начала. Для этого воспользуйтесь такой конструкцией:

for(End($Names); ($k=key($Names)); Prev($Names))

echo "Возраст $k – {$Names[$k]} лет\n";

По контексту несложно сообразить, как это работает. Функция End() устанавливает позицию текущего элемента в конец массива, а Prev() передвигает ее на один элемент назад. И еще. В PHP имеется функция current(). Она очень напоминает key(), только возвращает не ключ, а величину текущего элемента (если он не указывает на конец массива).

Недостатки косвенного перебора

Давайте теперь поговорим о достоинствах и недостатках такого вида перебора массивов. Основное достоинство – "читабельность" и ясность кода, а также то, что массив мы можем перебрать как в одну, так и в другую сторону. Однако существуют и недостатки.