Анимация
JavaScript


Главная  Библионтека 

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 [ 57 ] 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189

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

Еще несколько слов насчет операции слияния массивов. Цепочка

$z=$a+$b+$c+... и т. д.;

эквивалентна

$z=$a; $z+=$b; $z+=$c; ... и т. д.

Как нетрудно догадаться, оператор += для массивов делает примерно то же, что и оператор += для чисел, а именно - добавляет в свой левый операнд элементы, перечисленные в правом операнде-массиве, если они еще не содержатся в массиве слева.

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



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

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

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

Пусть $Names - список имен. Распечатаем их в столбик for($i=0; $i<count($Names); 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(), только возвращает не ключ, а величину текущего элемента (если он не указывает на конец массива).

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

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

Одинаковые ключи

Первый недостаток довольно фундаментален: мы не можем одновременно перебирать массив в двух вложенных циклах или функциях. Причина вполне очевидна: второй вложенный for "испортит" положение текущего элемента у первого forа. К сожалению, эту проблему никак нельзя обойти (разве что сделать копию массива, и во внутреннем цикле работать с ней, но это не очень-то красиво). Однако практика показывает, что такие переборы встречаются крайне редко.

Нулевой ключ

А что, если в массиве встретится ключ 0 (хотя для массивов имен это, согласитесь, маловероятно)? Давайте еще раз посмотрим на первый цикл перебора:

for(Reset($Names); ($k=key($Names)); Next($Names)) echo "Возраст $k - {$Names[$k]} лет\n";



0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 [ 57 ] 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189