Main Contents

Маленькие причуды массивов

January 4, 2008 by Scratch

Иногда самые простые вещи могут поставить в тупик. Например, такая банальная штука как удаление элемента из массива. Собственно, с одним таким багом я столкнулся сегодня, и хотел бы его описать.

Итак, представим ситуацию.  У нас есть JS код, в котором объявлен массив. Например, вида

var arr = [1,2,3,4,5,6,7];

Теперь перед нами стоит задача — удалить все четные элементы. Причем — удалить из исходного массива, а не получить новый

Для этого обычно пишется такая функция:

function cleanEven(arr) { 
    // проходим по всем элементам 
    for (var i = 0; i < arr.length; i++) { 
        // Если элемент  делится нацело на два 
        if ( ! (arr[i] % 2)) { 
            // Заменяем часть массива 
            // с позиции i, длиной 1 на пустоту 
            // (то есть удаляем i-тый элемент массива) 
            arr.splice(i, 1); 
        } 
    } 
}

После запуска и выполнения все вроде бы работает. В моем тестовом запуске все сработало нормально.

Но — попробуем этот же код на массиве



var arr = [1,2,3,4,4,3,2,1];

После выполнения функции над этим массивом мы обнаружим, что внутри массива осталась четверка.

В чем проблема?

Дело в том, что при удалении элемента все остальные элементы перемещаются.
То есть — если из массива [1,2,3,4] удалить элемент ‘2′, то останется массив [1,3,4]. Соответственно, индексы элементов сменятся, и, при проходе по массиву при помощи цикла, мы (после удаления элемента) просто пропускаем элемент, следующий сразу за ним.
Так, в случае двух четных чисел мы удаляем первое из них, и пропускаем второе.

Решение очень простое и элегантное –

function cleanEven(arr) { 
    // проходим по всем элементам НАЧИНАЯ С ПОСЛЕДНЕГО 
    for (var i = arr.length-1; i >= 0 ; i--) { 
        // Если элемент  делится нацело на два 
        if ( ! (arr[i] % 2)) { 
            // Заменяем часть массива 
            // с позиции i, длиной 1 на пустоту 
            // (то есть удаляем i-тый элемент массива) 
            arr.splice(i, 1); 
        } 
    } 
}

Filed under: Tips and tricks |

Leave a comment