Функция print_r() позволяет посмотреть на весь массив целиком, но не может выделить отдельные его части. Представьте себе задачу, когда требуется вывести из массива элементы, удовлетворяющие определенному условию. В этом случае функция print_r() не сможет нам помочь. Для решения подобных задач применяют операторы цикла. Но и здесь нас ожидают подводные камни. Сначала разберем самый простой случай, когда массив в качестве ключей имеет последовательный ряд чисел.
Воспользуемся оператором цикла for , так как его запись является очень компактной и практичной. Единственное, что нам надо выяснить, – это количество элементов в массиве. На практике очень часто для решения данной проблемы применяют функцию count(). В качестве входного параметра для нее является массив, а возвращает она количество элементов в нем.
Обход массива
Итак, предположим, что ключ первого элемента в нашем массиве будет 0. Таким образом, мы проходим по всем элементам массива и выводим их. В этот цикл уже можно добавить определенное условие, предъявляемое к элементам массива.
У вас может возникнуть вопрос о присутствии переменной $len_mass в программе, так как функцию count() можно компактно уместить во второе выражение цикла for. Сразу хочется сказать, что делать этого не следует, потому что при этом возникают два негативных момента. Во-первых, функция count() будет выполняться при каждой итерации, что увеличивает время обработки, а во-вторых, количество элементов массива может поменяться в теле цикла.
К сожалению а может и к счастью, рассматриваемый массив является лишь частным случаем. На практике обычно встречаются массивы с непоследовательной индексацией. Да и применение цикла for сегодня является неактуальным, так как есть специальная конструкция foreach, которая появилась только в четвертой версии РНР. В общем случае она выглядит так, как показано ниже.
Конструкция foreach
1 2 3 4 | foreach ($massiv as $key => $value) { // действия } |
В этой конструкции мы видим три переменные, среди которых $massiv – это просматриваемый массив. Переменные $кеу и $value (названия этих переменных вы выбираете сами) содержат соответственно ключ и значение. Итак, поясним ход работы этого оператора цикла на примере:
Обход массива с помощью конструкции foreach
Итак, в первой строчке мы создаем массив из трех элементов. Заметьте, что индексация производится с помощью строк. Далее следует конструкция, которая начинается со слова foreach. Затем в круглых скобках помещается рассматриваемый массив, после которого записывается специальное слово as. После него следует пара ключ-значение, разделяемая оператором =>.
Итак, на первой итерации переменной $kеу присваивается ключ первого элемента, а переменной $value – его значение. При следующей итерации в переменные $kеу и $value запишутся соответственно ключ и значение следующего элемента. И так далее, пока массив не будет пройден полностью.
Естественно, у вас может возникнуть вопрос о способе реализации этого цикла, так как механизм перемещения по массиву остается скрытым от программиста. Дело в том, что любой массив помимо ключей и значений имеет внутренний указатель (pointer) или курсор, с помощью которого можно узнать, какой элемент мы сейчас рассматриваем. Этим указателем, естественно, можно управлять, то есть переносить его от одного элемента к другому.
Для работы с указателем применяются функции list(), each(), count() и др.
Массив в 1С — это набор некоторых значений. Значения в одном массиве могут быть различных типов.
Массив может быть получен в результате выполнения различных функций, например, ВыгрузитьКолонку() таблицы значений; в виде массива можно получить выделенные строки динамического списка и т.д. Можно создать массив и «вручную».
Создание массива
1. Как создать массив нужного размера
пМассив = новый Массив(4 ) ; //создали массив из 4 элементов
ПМассив[
0
]
=
"Мы"
;
пМассив[
1
]
=
"создали"
;
пМассив[
2
]
=
"новый"
;
пМассив[
3
]
=
"массив"
;
2. Как создать пустой массив и добавить в него элементы
пМассив = новый Массив; //создали пустой массив
//Внесем значения элементов массива
ПМассив.
Добавить("Мы"
)
;
3. Как создать многомерный массив.
Рассмотрим этот вопрос на примере двумерного массива, так как массивы больших размерностей используются значительно реже, а механизм их работы не отличается от двумерного.
пМассив = новый Массив (4 , 2 ) ; //создали массив 4х2
//Внесем значения элементов массива, пронумеровав каждое слово
ПМассив[
0
]
[
0
]
=
"1. "
;
пМассив[
0
]
[
1
]
=
"Мы"
;
пМассив[
1
]
[
0
]
=
"2. "
;
пМассив[
1
]
[
1
]
=
"создали"
;
пМассив[
2
]
[
0
]
=
"3. "
;
пМассив[
2
]
[
1
]
=
"многомерный"
;
пМассив[
3
]
[
0
]
=
"4. "
;
пМассив[
3
]
[
1
]
=
"массив"
;
4. Как создать фиксированный массив
Фиксированный массив отличается от обычного тем, что его нельзя изменять. Нельзя добавлять, удалять или менять значения элементов такого массива.
Фиксированный массив может быть получен из обычного:
пМассив = новый Массив;
ПМассив.
Добавить("Мы"
)
;
пМассив.
Добавить("создали"
)
;
пМассив.
Добавить("новый"
)
;
пМассив.
Добавить("массив"
)
;
ФМассив = новый ФиксированныйМассив(пМассив) ; // создали фиксированный массив
Функции работы с массивами
Работу функций будем рассматривать на примере одномерного массива пМассив , созданного выше и состоящего из 4 элементов:
- «создали»
- «новый»
- «массив».
Функция ВГраница()
Получает наибольший индекс элемента массива. Он всегда на единицу меньше количества элементов массива.
Индекс = пМассив. ВГраница() // 3;
Функция Вставить()
Вставляет какое-то значение в элемент массива с указанным индексом. Последующие элементы массива сдвигаются
пМассив. Вставить(3 , "новое значение" ) //Теперь массив состоит из 5 элементов
Функция Добавить()
Создает новый элемент в конце массива и вставляет туда заданное значение
пМассив. Добавить("." ) // добавили точку пятым элементов массива;
Функция Количество()
Возвращает количество элементов массива.
пМассив. Количество() ; // 4
Функция Найти()
Ищет в массиве заданный элемент. Если находит, возвращает его индекс. Если не находит, возвращает Неопределено .
Индекс =
пМассив.
Найти("массив"
)
;
// 3
Индекс =
пМассив.
Найти("строка, которой не было"
)
;
// Неопределено
Функция Очистить()
Удаляет все значения из массива.
пМассив. Очистить() ;
Функция Получить()
Получает значение массива по индексу. Эту же задачу можно решить через .
Значение=
пМассив.
Получить(3
)
// "массив"
Значение=
пМассив[
3
]
;
// "массив"
Функция Удалить()
Удаляет элемент массива по индексу
пМассив. Удалить(3 ) ;
Функция Установить()
Устанавливает значение элемента массива по индексу. Работает аналогично .
пМассив.
Установить(3
,
"массив!"
)
;
пМассив[
3
]
=
"массив!"
;
Как обойти массив
Можно обойти все элементы массива без указания индекса:
Для
каждого ЭлементМассива из пМассив Цикл
Сообщить(ЭлементМассива)
;
КонецЦикла
;
Можно при обходе использовать индекс:
Для
Индекс=
0
по пМассив.
ВГраница()
Цикл
Сообщить(пМассив[
Индекс]
)
;
КонецЦикла
;
Как обойти многомерный массив
Многомерный массив обходится с помощью тех же циклов (см. выше), но один цикл должен быть вложен в другой.
Для
каждого Элемент1
из мМассив Цикл
Для
каждого Элемент2
из Элемент1
Цикл
Сообщить(Элемент1
)
;
КонецЦикла
;
КонецЦикла
;
Или с применением индексов.
мМассив= новый массив(3 , 4 ) ;
Для
Индекс1
=
0
по мМассив.
ВГраница()
Цикл
Для
Индекс2
по мМассив[
Индекс1
]
.
ВГраница()
Цикл
Сообщить(мМассив[
Индекс1
]
[
Индекс2
]
)
;
КонецЦикла
;
КонецЦикла
;
Сортировка массива
Для сортировки массива нам потребуется вспомогательный объект с типом СписокЗначений.
СписокЗнач
=
новый СписокЗначений;
// создаем список значений
СписокЗнач.
ЗагрузитьЗначения(пМассив)
;
// загружаем в список значения из массива
СписокЗнач.
СортироватьПоЗначению(НаправлениеСортировки.
Возр)
;
//сортируем по возрастанию
СписокЗнач.
СортироватьПоЗначению(НаправлениеСортировки.
Убыв)
;
//или по убыванию
пМассив=
СписокЗнач.
Выгрузить()
;
// выгружаем отсортированные значения обратно в массив
Сравнение двух массивов
Перед тем, как перейти к описанию функции сравнения, договоримся, что массивы считаются идентичными, если имеют одинаковое количество элементов и соответствующие элементы массивов равны. Тогда для сравнения можно использовать следующую функцию (кстати, такая функция уже присутствует в некоторых типовых конфигурациях):
Функция СравнитьМассивы(Массив1 , Массив2 )
Если
Массив1
.
Количество()
<>
Массив2
.
Количество()
Тогда
Возврат
ЛОЖЬ;
// Массивы не равны, сравнивать элементы нет смысла.
КонецЕсли
;
Для
Индекс=
0
по Массив1
.
ВГраница()
Цикл
Если
Массив1
[
Индекс]
<>
Массив2
[
Индекс]
Тогда
Возврат
Ложь
;
//эти элементы не равны, значит и массивы не равны
КонецЕсли
;
КонецЦикла
;
Возврат
Истина
;
// Если дошли до сюда, то массивы равны
КонецФункции
В функцию нужно передать 2 сравниваемых массива. Функция возвращает значение Истина , если массивы равны, и Ложь , если не равны.
- I. Перебор настоящих массивов
- Метод forEach и родственные методы
- Цикл for
- Правильное использование цикла for...in
- Цикл for...of (неявное использование итератора)
- Явное использование итератора
- Использование способов перебора настоящих массивов
- Преобразование в настоящий массив
- Замечание по объектам среды исполнения
I. Перебор настоящих массивов
На данный момент есть три способа перебора элементов настоящего массива:- метод Array.prototype.forEach ;
- классический цикл for ;
- «правильно» построенный цикл for...in .
- цикл for...of (неявное использование итератора);
- явное использование итератора.
1. Метод forEach и родственные методы
Если ваш проект рассчитан на поддержку возможностей стандарта ECMAScript 5 (ES5), вы можете использовать одно из его нововведений - метод forEach .Пример использования:
var a = ["a", "b", "c"];
a.forEach(function(entry) {
console.log(entry);
});
В общем случае использование forEach требует подключения библиотеки эмуляции es5-shim для браузеров, не имеющих нативной поддержки этого метода. К ним относятся IE 8 и более ранние версии, которые до сих пор кое-где еще используются.
К достоинствам forEach относится то, что здесь не нужно объявлять локальные переменные для хранения индекса и значения текущего элемента массива, поскольку они автоматически передаются в функцию обратного вызова (колбек) в качестве аргументов.
Если вас беспокоят возможные затраты на вызов колбека для каждого элемента, не волнуйтесь и прочитайте это .
ForEach предназначен для перебора всех элементов массива, но кроме него ES5 предлагает еще несколько полезных методов для перебора всех или некоторых элементов плюс выполнения при этом каких-либо действий с ними:
- every - возвращает true , если для каждого элемента массива колбек возвращает значение приводимое к true .
- some - возвращает true , если хотя бы для одного элемента массива колбек возвращает значение приводимое к true .
- filter - создает новый массив, включающий те элементы исходного массива, для которых колбек возвращает true .
- map - создает новый массив, состоящий из значений возращаемых колбеком.
- reduce - сводит массив к единственному значению, применяя колбек по очереди к каждому элементу массива, начиная с первого (может быть полезен для вычисления суммы элементов массива и других итоговых функций).
- reduceRight - работает аналогично reduce, но перебирает элементы в обратном порядке.
2. Цикл for
Старый добрый for рулит :Var a = ["a", "b", "c"];
var index;
for (index = 0; index < a.length; ++index) {
console.log(a);
}
Если длина массива неизменна в течение всего цикла, а сам цикл принадлежит критическому в плане производительности участку кода (что маловероятно), то можно использовать «более оптимальную» версию for с хранением длины массива:
Var a = ["a", "b", "c"];
var index, len;
for (index = 0, len = a.length; index < len; ++index) {
console.log(a);
}
Теоретически этот код должен выполняться чуть быстрее, чем предыдущий.
Если порядок перебора элементов не важен, то можно пойти еще дальше в плане оптимизации и избавиться от переменной для хранения длины массива, изменив порядок перебора на обратный:
Var a = ["a", "b", "c"];
var index;
for (index = a.length - 1; index >= 0; --index) {
console.log(a);
}
Тем не менее, в современных движках JavaScript подобные игры с оптимизацией обычно ничего не значат.
3. Правильное использование цикла for...in
Если вам посоветуют использовать цикл for...in , помните, что перебор массивов - не то, для чего он предназначен . Вопреки распространенному заблуждению цикл for...in перебирает не индексы массива, а перечислимые свойства объекта.Тем не менее, в некоторых случаях, таких как перебор разреженных массивов , for...in может оказаться полезным, если только соблюдать при этом меры предосторожности, как показано в примере ниже:
// a - разреженный массив
var a = ;
a = "a";
a = "b";
a = "c";
for (var key in a) {
if (a.hasOwnProperty(key) &&
/^0$|^\d*$/.test(key) &&
key <= 4294967294) {
console.log(a);
}
}
В данном примере на каждой итерации цикла выполняется две проверки:
- то, что массив имеет собственное свойство с именем key (не наследованное из его прототипа).
- то, что key - строка, содержащая десятичную запись целого числа, значение которого меньше 4294967294 . Откуда берется последнее число? Из определения индекса массива в ES5, из которого следует, что наибольший индекс, который может иметь элемент в массиве: (2^32 - 2) = 4294967294 .
Чтобы не писать такой громоздкий код проверок каждый раз, когда требуется перебор массива, можно оформить его в виде отдельной функции:
Function arrayHasOwnIndex(array, key) {
return array.hasOwnProperty(key) && /^0$|^\d*$/.test(key) && key <= 4294967294;
}
Тогда тело цикла из примера значительно сократится:
For (key in a) {
if (arrayHasOwnIndex(a, key)) {
console.log(a);
}
}
Рассмотренный выше код проверок является универсальным, подходящим для всех случаев. Но вместо него можно использовать более короткую версию, хотя формально и не совсем правильную, но, тем не менее, подходящую для большинства случаев:
For (key in a) { if (a.hasOwnProperty(key) && String(parseInt(key, 10)) === key) { console.log(a); } }
4. Цикл for...of (неявное использование итератора)
ES6, пока все еще пребывающий в статусе черновика , должен ввести в JavaScript итераторы.Итератор
- это реализуемый объектом протокол, который определяет стандартный способ получения последовательности значений (конечной или бесконечной).
Итератор - это объект, в котором определен метод next() - функция без аргументов, возвращающая объект с двумя свойствами:
- done (boolean) - принимает значение true , если итератор достиг конца итерируемой последовательности. В противном случае имеет значение false .
- value - определяет значение, возвращаемое итератором. Может быть не определено (отсутствовать), если свойство done имеет значение true .
Пример использования for...of:
Var val;
var a = ["a", "b", "c"];
for (val of a) {
console.log(val);
}
В приведенном примере цикл for...of неявно вызывает итератор объекта Array для получения каждого значения массива.
5. Явное использование итератора
Итераторы можно также использовать и явно, правда, в этом случае код становится значительно сложнее, по сравнению с циклом for...of . Выглядит это примерно так:Var a = ["a", "b", "c"];
var it = a.entries();
var entry;
while (!(entry = it.next()).done) {
console.log(entry.value);
}
В данном примере метод Array.prototype.entries возвращает итератор, который используется для вывода значений массива. На каждой итерации entry.value содержит массив вида [ключ, значение] .
II. Перебор массивоподобных объектов
Кроме настоящих массивов, в JavaScript встречаются также массивоподобные объекты . С настоящими массивами их роднит то, что они имеют свойство length и свойства с именами в виде чисел, соответствующие элементам массива. В качестве примеров можно назвать DOM коллекции NodeList и псевдомассив arguments , доступный внутри любой функции/метода.1. Использование способов перебора настоящих массивов
Как минимум большинство, если не все, способы перебора настоящих массивов могут быть применены для перебора массивоподобных объектов.Конструкции for и for...in могут быть применены к массивоподобным объектам точно тем же путем, что и к настоящим массивам.
ForEach и другие методы Array.prototype также применимы к массивоподобным объектам. Для этого нужно использовать вызов Function.call или Function.apply .
Например, если вы хотите применить forEach к свойству childNodes объекта Node , то это делается так:
Array.prototype.forEach.call(node.childNodes, function(child) {
// делаем что-нибудь с объектом child
});
Для удобства повторного использования этого приема, можно объявить ссылку на метод Array.prototype.forEach в отдельной переменной и использовать ее как сокращение:
// (Предполагается, что весь код ниже находится в одной области видимости)
var forEach = Array.prototype.forEach;
// ...
forEach.call(node.childNodes, function(child) {
// делаем что-нибудь с объектом child
});
Если в массивоподобном объекте имеется итератор, то его можно использовать явно или неявно для перебора объекта таким же способом, как и для настоящих массивов.
2. Преобразование в настоящий массив
Есть также еще один, очень простой, способ перебора массивоподобного объекта: преобразовать его в настоящий массив и использовать любой из рассмотренных выше способов перебора настоящих массивов. Для преобразования можно использовать универсальный метод Array.prototype.slice , который может быть применен к любому массивоподобному объекту. Делается это очень просто, как показано в примере ниже:Var trueArray = Array.prototype.slice.call(arrayLikeObject, 0);
Например, если вы хотите преобразовать коллекцию NodeList в настоящий массив, вам нужен примерно такой код:
Var divs = Array.prototype.slice.call(document.querySelectorAll("div"), 0);
Update
: Как было отмечено в комментариях rock и torbasow , в ES6 вместо Array.prototype.slice можно использовать более наглядный метод Array.from .
3. Замечание по объектам среды исполнения
Если вы применяете методы Array.prototype к объектам среды исполнения (таких как DOM коллекции), то вы должны иметь в виду, что правильная работа этих методов не гарантирована во всех средах исполнения (в т.ч. в браузерах). Это зависит от поведения конкретного объекта в конкретной среде исполнения, если точнее, от того, как в этом объекте реализована абстрактная операция HasProperty . Проблема в том, что сам стандарт ES5 допускает возможность неправильного поведения объекта по отношению к этой операции (см. §8.6.2).Поэтому важно тестировать работу методов Array.prototype в каждой среде исполнения (браузере), в которой планируется использование вашего приложения.