- Объявление
- Методы
pop/push,shift/unshift - Внутреннее устройство массива
- Перебор элементов
- Особенности работы
length - Еще о создании массивов
- Итого
При создании электронного магазина, нужно работать со списком товаров. Для хранения такого списка удобнее всего использовать массив.
Массив с числовыми индексами - это коллекция данных, которая хранит сколько угодно значений, причем у каждого значения - свой уникальный номер.
Если переменная - это коробка для данных, то массив - это шкаф с нумерованными ячейками, в каждой из которых могут быть свои данные.
Например, при создании электронного магазина нужно хранить список товаров - для таких задач и придуман массив.
Объявление
Синтаксис для создания нового массива — квадратные скобки со списком элементов внутри. Например, создадим массив fruits с тремя элементами:
var fruits = ["Яблоко", "Апельсин", "Слива"];
Элементы нумеруются, начиная с нуля. Чтобы получить нужный элемент из массива — указывается его номер в квадратных скобках:
var fruits = ["Яблоко", "Апельсин", "Слива"]; alert(fruits[0]); // Яблоко alert(fruits[1]); // Апельсин alert(fruits[2]); // Слива
Элемент можно всегда заменить:
fruits[2] = 'Груша'; // теперь ["Яблоко", "Апельсин", "Груша"]… Или добавить:
fruits[3] = 'Лимон'; // теперь ["Яблоко", "Апельсин", "Груша", "Лимон"]
Общее число элементов, хранимых в массиве, содержится в его свойстве length:
var fruits = ["Яблоко", "Апельсин", "Груша"]; alert(fruits.length); // 3
Через alert можно вывести и массив целиком. При этом его элементы будут перечислены через запятую:
var fruits = ["Яблоко", "Апельсин", "Груша"]; alert(fruits); // Яблоко,Апельсин,Груша
В массиве может храниться любое число элементов любого типа. В том числе, строки, числа, объекты и т.п.:
// микс значений
var arr = [ 1, function(a) { alert(a) }, 'Имя', { name: 'Петя' }, true ];
// получить функцию из массива и тут же вызвать
arr[1]("тест");
Как получить последний элемент из произвольного массива?
У нас есть массив goods. Сколько в нем элементов - не знаем, но можем прочитать из goods.length. Напишите код для получения последнего элемента goods.
Последний элемент имеет индекс на 1 меньший, чем длина массива.
Например:
var fruits = ["Яблоко", "Груша", "Слива"];
Длина массива этого массива fruits.length равна 3. Здесь «Яблоко» имеет индекс 0, «Груша» - индекс 1, «Слива» - индекс 2.
То есть, для массива длины goods:
var lastItem = goods[goods.length-1]; // последний элемент
Как добавить элемент в конец произвольного массива?
У нас есть массив goods. Напишите код для добавления в его конец значения «Компьютер».
Текущий последний элемент имеет индекс goods.length-1. Значит, индексом нового элемента будет goods.length:
goods[goods.length] = 'Компьютер'
Методы pop/push, shift/unshift
Одно из применений массива — это очередь. В классическом программировании так называют упорядоченную коллекцию элементов, такую что элементы добавляются в конец, а обрабатываются — с начала.
В реальной жизни эта структура данных встречается очень часто. Например, очередь сообщений, которые надо отослать.
Очень близка к очереди еще одна структура данных: стек. Это такая коллекция элементов, в которой новые элементы добавляются в конец и берутся с конца.
Например, стеком является колода карт, в которую новые карты кладутся сверху, и берутся — тоже сверху.
Для того, чтобы реализовывать эти структуры данных, и просто для более удобной работы с началом и концом массива существуют специальные методы.
Конец массива
pop- Удаляет последний элемент из массива и возвращает его:
var fruits = ["Яблоко", "Апельсин", "Груша"]; alert( fruits.pop() ); // удалили "Груша" alert(fruits); // Яблоко, Апельсин
push- Добавляет элемент в конец массива:
var fruits = ["Яблоко", "Апельсин"]; fruits.push("Груша"); alert(fruits); // Яблоко, Апельсин, ГрушаЯвляется полным аналогом
fruits[fruits.length] = ....
Начало массива
shift- Удаляет из массива первый элемент и возвращает его:
var fruits = ["Яблоко", "Апельсин", "Груша"]; alert( fruits.shift() ); // удалили Яблоко alert(fruits); // Апельсин, Груша
unshift- Добавляет элемент в начало массива:
var fruits = ["Апельсин", "Груша"]; fruits.unshift('Яблоко'); alert(fruits); // Яблоко, Апельсин, Груша

Методы push и unshift могут добавлять сразу по несколько элементов:
var fruits = ["Яблоко"];
fruits.push("Апельсин", "Персик");
fruits.unshift("Ананас", "Лимон");
// результат: ["Ананас", "Лимон", "Яблоко", "Апельсин", "Персик"]
Задача из 5 шагов-строк:
- Создайте массив
stylesс элементами «Джаз», «Блюз». - Добавьте в конец значение «Рок-н-Ролл»
- Замените предпоследнее значение с конца на «Классика». Код замены предпоследнего значения должен работать для массивов любой длины.
- Удалите первое значение массива и выведите его
alert. - Добавьте в начало значения «Рэп» и «Регги».
Массив в результате каждого шага:
Джаз, Блюз Джаз, Блюз, Рок-н-Ролл Джаз, Классика, Рок-н-Ролл Классика, Рок-н-Ролл Рэп, Регги, Классика, Рок-н-Ролл
var styles = ["Джаз", "Блюз"];
styles.push("Рок-н-Ролл");
styles[styles.length-2] = "Классика";
alert( styles.shift() );
styles.unshift( "Рэп", "Регги ");
Напишите код для вывода alert случайного значения из массива:
var arr = ["Яблоко", "Апельсин", "Груша", "Лимон"];
P.S. Код для генерации случайного целого от min to max включительно:
var rand = min + Math.floor( Math.random() * (max+1-min) );
Для вывода нужен случайный номер от 0 до arr.length-1 включительно.
var arr = ["Яблоко", "Апельсин", "Груша", "Лимон"]; var rand = Math.floor( Math.random() * arr.length ); alert(arr[rand]);
Создайте объект calculator с методами:
readValues(n)запрашиваетnзначений и сохраняет их в массиве - свойстве объекта.sum()возвращает сумму всех значенийmul()возвращает произведение всех значений
На демо-страничке tutorial/intro/object/calculatorMany.html показан результат кода:
var calculator = {
... ваш код...
}
calculator.readValues(3); // ввод: 1, 2, 5
alert( calculator.sum() ); // результат: 8
alert( calculator.mul() ); // результат: 10
Внутреннее устройство массива
Методы push/pop выполняются быстро, а shift/unshift - медленно. Почему так?
Чтобы понять, почему работать с концом массива - быстрее, чем с его началом, посмотрим как массив устроен внутри.
Как мы уже говорили, массив - это «шкаф с нумерованными ячейками». Фактически, массив — это объект, где в качестве ключей выбраны цифры, с дополнительными методами и свойством length.
Так как это объект, то никто не мешает сделать следующее:
var fruits = []; // создать массив fruits[99999] = 5; // присвоить свойство с любым номером fruits.age = 25; // назначить свойство со строковым именем
.. Но массивы для того и придуманы в JavaScript, чтобы удобно работать именно с упорядоченными, нумерованными данными. Для этого в них существуют специальные методы и свойство length.
Как правило, нет причин использовать массив как обычный объект, хотя технически это и возможно.
Влияние на быстродействие
Операция shift выполняет два действия:
- Удалить элемент в начале.
- Обновить внутреннее свойство
length.
При этом, так как все элементы находятся в своих ячейках, просто очистить ячейку с номером 0 недостаточно. Нужно еще и переместить все ячейки на 1 вниз (красным на рисунке подсвечены изменения):
*!*fruits.shift();*/!* // убрать 1 элемент с начала
Чем больше элементов в массиве, тем дольше их перемещать.
Аналогично работает unshift: чтобы добавить элемент в начало массива, нужно сначала перенести все существующие.
У методов push/pop таких проблем нет. Для того, чтобы удалить элемент, метод pop очищает ячейку и укорачивает length.
*!*fruits.pop();*/!* // убрать 1 элемент с конца

Аналогично работает push.
Перебор элементов
Для перебора элементов обычно используется цикл:
var fruits = ["Яблоко", "Апельсин", "Груша"];
for (var i=0; i<fruits.length; i++) {
alert(fruits[i]);
}
Особенности работы length
Используем length для укорачивания массива
Встроенные методы для работы с массивом автоматически обновляют его длину length. Обычно нам не нужно самостоятельно менять это свойство.
Но есть один фокус, который можно провернуть. Дело в том, что при уменьшении length массив укорачивается. Причем этот процесс необратимый, т.е. даже если потом вернуть length обратно — значения не восстановятся:
var arr = [0, 1, 2, 3] arr.length = 2; // укоротить до 2 элементов, т.е [0,1] arr.length = 4; // вернуть `length` (в тестовых целях) alert(arr[3]); // значение исчезло
Самый простой способ очистить массив — это arr.length=0.
length = последний индекс + 1
Свойство length - не количество элементов массива, а последний индекс + 1. Так уж оно устроено.
Это позволяет разрешить дилемму «чему равно length если присвоена одна ячейка с номером 1000?». Конечно же, 1001.
var arr = []; arr[1000] = true; alert(arr.length); // *!*1001*/!*
В реальной жизни в таких случаях рекомендуется использовать обычные объекты, т.к. методы массивов продуманы для работы с последовательной нумерацией.
Еще о создании массивов
new Array()
Существует еще один синтаксис для создания массива:
var arr = new Array("Яблоко", "Груша", "и т.п.");
Он редко используется, т.к. квадратные скобки [] короче.
Кроме того, у него есть одна особенность. Вызов new Array(number) с единственным аргументом — числом создает массив без элементов, но с заданной длиной.
var arr = new Array(2,3) // создает массив [2, 3] arr = new Array(2) // создаст массив [2] ? alert(arr[0]) // нет! у нас массив без элементов, длины 2
Что же такое этот «массив без элементов, но с длиной»? Как такое возможно?
Оказывается, очень даже возможно и соответствует объекту {length: 2}. Получившийся массив ведёт себя так, как будто его элементы равны undefined.
Это может быть неожиданным сюрпризом, поэтому обычно используют квадратные скобки.
Многомерные массивы
Массивы в JavaScript могут содержать в качестве элементов другие массивы. Это можно использовать для создания многомерных массивов, например матриц:
var matrix = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]; alert(matrix[1][1]); // центральный элемент
Итого
Массивы существуют для работы с упорядоченным набором элементов.
Объявление:
// предпочтительное var arr = [ элемент1, элемент2... ]; // new Array var arr = new Array( элемент1, элемент2...);;
При этом new Array(число) создаёт массив заданной длины, без элементов. Чтобы избежать ошибок, предпочтителен первый синтаксис.
Свойство length — длина массива. Если точнее, то последний индекс массива плюс 1. Если её уменьшить вручную, то массив укоротится. Если length больше реального количества элементов, то отсутствующие элементы равны undefined.
Массив можно использовать как очередь или стек.
Операции с концом массива:
arr.push(элемент1, элемент2...)добавляет элементы в конец.var elem = arr.pop()удаляет и возвращает последний элемент.
Операции с началом массива:
arr.unshift(элемент1, элемент2...)добавляет элементы в начало.var elem = arr.shift()удаляет и возвращает первый элемент.
Эти операции перенумеровывают все элементы, поэтому работают медленно.
В следующей главе мы рассмотрим другие методы для работы с массивами.
Создайте функцию find(arr, value), которая ищет в массиве arr значение value и возвращает его номер, если найдено или -1, если не найдено.
Например:
arr = [ "test", 2, 1.5, false ]; find(arr, "test"); // 0 find(arr, 2); // 1 find(arr, 1.5); // 2 find(arr, 0); // -1
Возможное решение:
function find(array, value) {
for(var i=0; i<array.length; i++) {
if (array[i] == value) return i;
}
return -1;
}
Однако, в нем ошибка, т.к. сравнение == не различает 0 и false.
Поэтому лучше использовать ===. Кроме того, в современном стандарте JavaScript существует встроенная фунция Array#indexOf, которая работает именно таким образом. Имеет смысл ей воспользоваться, если браузер ее поддерживает.
function find(array, value) {
if (array.indexOf) { // если метод существует
return array.indexOf(value);
}
for(var i=0; i<array.length; i++) {
if (array[i] === value) return i;
}
return -1;
}
var arr = ["a", -1, 2, "b"];
var index = find(arr, 2);
alert(index);
… Но еще лучшим вариантом было бы определить find по-разному в зависимости от поддержки браузером метода indexOf:
// создаем пустой массив и проверяем поддерживается ли indexOf
if ( [].indexOf ) {
var find = function(array, value) {
return array.indexOf(value);
}
} else {
var find = function(array, value) {
for(var i=0; i<array.length; i++) {
if (array[i] === value) return i;
}
return -1;
}
}
Этот способ - лучше всего, т.к. не требует при каждом запуске find проверять поддержку indexOf.
Создайте фунцию filterRange(arr, a, b), которая принимает массив чисел arr и возвращает новый массив, который содержит только те числа из arr, которые находятся между a и b включительно.
То есть, проверка имеет вид a ≤ arr[i] ≤ b. Функция не должна менять arr.
Пример работы:
var arr = [5, 4, 3, 8, 0]; var filtered = filterRange(arr, 3, 5); // теперь filtered = [5, 4, 3] // arr не изменился
Алгоритм решения:
- Создайте временный пустой массив
var results = []. - Пройдите по элементам
arrв цикле и заполните его. - Возвратите
results.
Создайте функцию filter(arr, func), которая получает массив arr и возвращает новый, в который входят только те элементы arr, для которых func возвращает true.
Пример, как это должно работать:
var arr = [1, 2, 3, 4, 5, 6, 7]
var res = filter(arr, function(a) { return a>=3 && a <= 5; });
alert(res); // результат: 3, 4, 5
Целое число, большее 1, называется простым, если оно не делится нацело ни на какое другое, кроме себя и 1.
Древний алгоритм «Решето Эратосфена» для поиска всех простых чисел до n выглядит так:
- Создать список последовательных чисел от
2доn:2, 3, 4, ..., n. - Пусть
p=2, это первое простое число. - Зачеркнуть все числа в списке с разницей в
p, т.е.2p, 3p, 4pи т.д. В случаеp=2это будут2,4,6,8.... - Поменять значение
pна первое незачеркнутое число послеp. - Повторить шаги 3-4 пока
p2 < n. - Все оставшиеся незачеркнутыми числа - простые.
Посмотрите также анимацию алгоритма.
Реализуйте «Решето Эратосфена» в JavaScript. Найдите все простые числа до 100 и выведите их сумму.
Задаче ниже — «на подумать», она не обязательна.
На входе массив чисел, например: arr = [1, -2, 3, 4, -9, 6].
Задача — найти непрерывный подмассив arr, сумма элементов которого максимальна.
Ваша функция должна возвращать только эту сумму.
Например:
getMaxSubSum([-1, *!*2, 3*/!*, -9]) = 5 (сумма выделенных) getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) = 11 getMaxSubSum([-2, -1, *!*1, 2*/!*]) = 3 getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) = 100 getMaxSubSum([*!*1, 2, 3*/!*]) = 6 (неотрицательные - берем всех) getMaxSubSum([-1, -2, -3]) = 0 (все отрицательные, не берем ничего)
Постарайтесь придумать решение, которое работает за O(n2), а лучше за O(n) операций.
Можно просто посчитать для каждого элемента массива все суммы, которые с него начинаются.
Например, для [-1, 2, 3, -9, 11]:
// Начиная с -1: -1 -1 + 2 -1 + 2 + 3 -1 + 2 + 3 + (-9) -1 + 2 + 3 + (-9) + 11 // Начиная с 2: 2 2 + 3 2 + 3 + (-9) 2 + 3 + (-9) + 11 // Начиная с 3: 3 3 + (-9) 3 + (-9) + 11 // Начиная с -9 -9 -9 + 11 // Начиная с -11 -11
Сделайте вложенный цикл, который на внешнем уровне бегает по элементам массива, а на внутреннем — формирует все суммы элементов, которые начинаются с текущей позиции.
function getMaxSubSum(arr) {
var maxSum = 0; // если совсем не брать элементов, то сумма 0
for(var i=0; i<arr.length; i++) {
var sumFixedStart = 0;
for(var j=i; j<arr.length; j++) {
sumFixedStart += arr[j];
maxSum = Math.max(maxSum, sumFixedStart);
}
}
return maxSum;
}
alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5
alert( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11
alert( getMaxSubSum([-2, -1, 1, 2]) ); // 3
alert( getMaxSubSum([1, 2, 3]) ); // 6
alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100
Будем идти по массиву и накапливать в некоторой переменной s текущую частичную сумму. Если в какой-то момент s окажется отрицательной, то мы просто присвоим s=0. Утверждается, что максимум из всех значений переменной s, случившихся за время работы, и будет ответом на задачу.
Докажем этот алгоритм.
В самом деле, рассмотрим первый момент времени, когда сумма s стала отрицательной. Это означает, что, стартовав с нулевой частичной суммы, мы в итоге пришли к отрицательной частичной сумме — значит, и весь этот префикс массива, равно как и любой его суффикс имеют отрицательную сумму.
Следовательно, от всего этого префикса массива в дальнейшем не может быть никакой пользы: он может дать только отрицательную прибавку к ответу.
function getMaxSubSum(arr) {
var maxSum = 0, partialSum = 0;
for (var i=0; i<arr.length; i++) {
partialSum += arr[i];
maxSum = Math.max(maxSum, partialSum);
if (partialSum < 0) partialSum = 0;
}
return maxSum;
}
alert( getMaxSubSum([-1, 2, 3, -9]) ); // 5
alert( getMaxSubSum([-1, 2, 3, -9, 11]) ); // 11
alert( getMaxSubSum([-2, -1, 1, 2]) ); // 3
alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100
alert( getMaxSubSum([1, 2, 3]) ); // 6
alert( getMaxSubSum([-1, -2, -3]) ); // 0
Информацию об алгоритме вы также можете прочитать здесь: http://e-maxx.ru/algo/maximum_average_segment и здесь: Maximum subarray problem.
Комментарии
- Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
- Если ваш комментарий касается задачи -- откройте её в отдельном окне и напишите там.
- Комментарии без смысла, с рекламой или не о статье вообще - удаляются.