Удаление элементов массива в JavaScript - удаление против сращивания

В чем разница между использованием delete оператор элемента массива, в отличие от использования Array.splice метод?

Например:

myArray = ['a', 'b', 'c', 'd'];

delete myArray[1];
//  or
myArray.splice (1, 1);

Зачем даже метод сращивания, если я могу удалять элементы массива, как я могу с объектами?

29 ответов

Решение

delete удалит свойство объекта, но не переиндексирует массив или не обновит его длину. Это делает его похожим на неопределенное:

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> delete myArray[0]
  true
> myArray[0]
  undefined

Обратите внимание, что на самом деле это значение не установлено undefined скорее свойство удаляется из массива, что делает его неопределенным. Инструменты разработчика Chrome проясняют это различие, печатая empty при входе в массив.

> myArray[0]
  undefined
> myArray
  [empty, "b", "c", "d"]

myArray.splice(start, deleteCount) фактически удаляет элемент, переиндексирует массив и изменяет его длину.

> myArray = ['a', 'b', 'c', 'd']
  ["a", "b", "c", "d"]
> myArray.splice(0, 2)
  ["a", "b"]
> myArray
  ["c", "d"]

Метод Array.remove()

Джон Резиг, создатель jQuery, создал очень удобный Array.remove метод, который я всегда использую в своих проектах.

// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
  var rest = this.slice((to || from) + 1 || this.length);
  this.length = from < 0 ? this.length + from : from;
  return this.push.apply(this, rest);
};

и вот несколько примеров того, как это можно использовать:

// Remove the second item from the array
array.remove(1);
// Remove the second-to-last item from the array
array.remove(-2);
// Remove the second and third items from the array
array.remove(1,2);
// Remove the last and second-to-last items from the array
array.remove(-2,-1);

Сайт Джона

Поскольку delete удаляет только объект из элемента в массиве, длина массива не изменится. Splice удаляет объект и сокращает массив.

Следующий код будет отображать "a", "b", "undefined", "d"

myArray = ['a', 'b', 'c', 'd']; delete myArray[2];

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

Принимая во внимание, что это будет отображать "a", "b", "d"

myArray = ['a', 'b', 'c', 'd']; myArray.splice(2,1);

for (var count = 0; count < myArray.length; count++) {
    alert(myArray[count]);
}

Я наткнулся на этот вопрос, пытаясь понять, как удалить каждое вхождение элемента из массива. Вот сравнение splice а также delete для удаления каждого 'c' от items Массив.

var items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  items.splice(items.indexOf('c'), 1);
}

console.log(items); // ["a", "b", "d", "a", "b", "d"]

items = ['a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'];

while (items.indexOf('c') !== -1) {
  delete items[items.indexOf('c')];
}

console.log(items); // ["a", "b", undefined, "d", "a", "b", undefined, "d"]
​

Из Базовой Справки по JavaScript 1.5> Операторы> Специальные операторы> Оператор удаления:

Когда вы удаляете элемент массива, длина массива не изменяется. Например, если вы удалите [3], a[4] по-прежнему будет [4], а [3] не определено. Это верно, даже если вы удалите последний элемент массива (delete a[a.length-1]).

Как говорилось много раз выше, используя splice() кажется идеально подходит. Документация в Mozilla:

splice() Метод изменяет содержимое массива, удаляя существующие элементы и / или добавляя новые элементы.

var myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

myFish.splice(2, 0, 'drum'); 
// myFish is ["angel", "clown", "drum", "mandarin", "sturgeon"]

myFish.splice(2, 1); 
// myFish is ["angel", "clown", "mandarin", "sturgeon"]

Синтаксис

array.splice(start)
array.splice(start, deleteCount)
array.splice(start, deleteCount, item1, item2, ...)

параметры

Начните

Индекс, с которого начинается изменение массива. Если он больше длины массива, фактический начальный индекс будет установлен равным длине массива. Если отрицательно, начнется так много элементов с конца.

deleteCount

Целое число, указывающее количество удаляемых старых элементов массива. Если deleteCount равен 0, элементы не удаляются. В этом случае вы должны указать хотя бы один новый элемент. Если deleteCount больше, чем количество элементов, оставшихся в массиве, начиная с начала, то все элементы до конца массива будут удалены.

Если deleteCount не указан, deleteCount будет равен (arr.length - start).

item1, item2, ...

Элементы, добавляемые в массив, начиная с начального индекса. Если вы не указываете какие-либо элементы, splice() удалит только элементы из массива.

Возвращаемое значение

Массив, содержащий удаленные элементы. Если удаляется только один элемент, возвращается массив из одного элемента. Если никакие элементы не удалены, возвращается пустой массив.

[...]

splice будет работать с числовыми индексами.

в то время как delete может быть использован против других видов индексов..

пример:

delete myArray['text1'];

Вероятно, также стоит упомянуть, что сплайс работает только с массивами. (На свойства объекта нельзя полагаться, чтобы следовать последовательному порядку.)

Чтобы удалить пару ключ-значение из объекта, фактически удалите то, что вам нужно:

delete myObj.propName;     // , or:
delete myObj["propName"];  // Equivalent.

удалить против сращивания

когда вы удаляете элемент из массива

var arr = [1,2,3,4]; delete arr[2]; console.log(arr)
//result
[1, 2, 3:, 4]

когда ты склеиваешь

var arr = [1,2,3,4]; arr.splice(1,1); console.log(arr)
//result
 [1, 3, 4]

в случае удаления элемент удаляется, но индекс остается пустым

в то время как в случае сращивания элемент удаляется, а индекс остальных элементов соответственно уменьшается

Разницу можно увидеть, зарегистрировав длину каждого массива после delete оператор и splice() метод применяется. Например:

оператор удаления

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
delete trees[3];

console.log(trees); // ["redwood", "bay", "cedar", empty, "maple"]
console.log(trees.length); // 5

delete Оператор удаляет элемент из массива, но "заполнитель" элемента все еще существует. oak был удален, но все еще занимает место в массиве. Из-за этого длина массива остается 5.

метод splice()

var trees = ['redwood', 'bay', 'cedar', 'oak', 'maple'];
trees.splice(3,1);

console.log(trees); // ["redwood", "bay", "cedar", "maple"]
console.log(trees.length); // 4

splice() Метод полностью удаляет целевое значение, а также "заполнитель". oak был удален, а также пространство, которое он занимал в массиве. Длина массива теперь 4.

delete действует как нереальная ситуация, он просто удаляет элемент, но длина массива остается неизменной:

пример из узла терминала:

> var arr = ["a","b","c","d"];
> delete arr[2]
true
> arr
[ 'a', 'b', , 'd', 'e' ]

Вот функция для удаления элемента массива по индексу, используя slice (), она принимает arr в качестве первого аргумента и индекс члена, который вы хотите удалить в качестве второго аргумента. Как вы можете видеть, он фактически удаляет член массива и уменьшит длину массива на 1

function(arr,arrIndex){
    return arr.slice(0,arrIndex).concat(arr.slice(arrIndex + 1));
}

Функция, приведенная выше, заключается в получении всех элементов до индекса и всех членов после индекса, объединяет их вместе и возвращает результат.

Вот пример использования вышеуказанной функции в качестве модуля узла, где будет полезен терминал:

> var arr = ["a","b","c","d"]
> arr
[ 'a', 'b', 'c', 'd' ]
> arr.length
4 
> var arrayRemoveIndex = require("./lib/array_remove_index");
> var newArray = arrayRemoveIndex(arr,arr.indexOf('c'))
> newArray
[ 'a', 'b', 'd' ] // c ya later
> newArray.length
3

обратите внимание, что это не будет работать с одним массивом, содержащим дубликаты, потому что indexOf("c") просто получит первое вхождение, и только склеит и удалит первый найденный символ "c".

Вы можете использовать что-то вроде этого

var my_array = [1,2,3,4,5,6];
delete my_array[4];
console.log(my_array.filter(function(a){return typeof a !== 'undefined';}));

Должен отображаться [1, 2, 3, 4, 6]

Если вы хотите выполнить итерацию большого массива и выборочно удалить элементы, было бы дорого вызывать splice() для каждого удаления, так как splice() должен будет каждый раз переиндексировать последующие элементы. Поскольку массивы являются ассоциативными в Javascript, было бы более эффективно удалить отдельные элементы, а затем повторно индексировать массив впоследствии.

Вы можете сделать это, создав новый массив. например

function reindexArray( array )
{
       var result = [];
        for( var key in array )
                result.push( array[key] );
        return result;
};

Но я не думаю, что вы можете изменить значения ключей в исходном массиве, что было бы более эффективно - похоже, вам, возможно, придется создать новый массив.

Обратите внимание, что вам не нужно проверять "неопределенные" записи, так как они на самом деле не существуют и цикл for не возвращает их. Это артефакт печати массива, который отображает их как неопределенные. Они, кажется, не существуют в памяти.

Было бы хорошо, если бы вы могли использовать что-то вроде slice(), которое было бы быстрее, но не переиндексирует. Кто-нибудь знает лучший способ?


На самом деле, вы, вероятно, можете сделать это на месте следующим образом, что, вероятно, является более эффективным, с точки зрения производительности:

reindexArray : function( array )
{
    var index = 0;                          // The index where the element should be
    for( var key in array )                 // Iterate the array
    {
        if( parseInt( key ) !== index )     // If the element is out of sequence
        {
            array[index] = array[key];      // Move it to the correct, earlier position in the array
            ++index;                        // Update the index
        }
    }

    array.splice( index );  // Remove any remaining elements (These will be duplicates of earlier items)
},

Производительность

Уже есть много хороших ответов о функциональных различиях, поэтому здесь я хочу сосредоточиться на производительности. Сегодня (2020.06.25) я выполняю тесты для Chrome 83.0, Safari 13.1 и Firefox 77.0 для решений, упомянутых в вопросе, и дополнительно из выбранных ответов

Выводы

  • в splice (B) быстрое решение для малых и больших массивов
  • в delete (A) решение является самым быстрым для больших и средних быстрых для небольших массивов
  • в filter (E) решение является самым быстрым в Chrome и Firefox для небольших массивов (но самым медленным в Safari и медленным для больших массивов)
  • решение D довольно медленное
  • решение C не работает для больших массивов в Chrome и Safari
    function C(arr, idx) {
      var rest = arr.slice(idx + 1 || arr.length);
      arr.length = idx < 0 ? arr.length + idx : idx;
      arr.push.apply(arr, rest);
      return arr;
    }
    
    
    // Crash test
    
    let arr = [...'abcdefghij'.repeat(100000)]; // 1M elements
    
    try {
     C(arr,1)
    } catch(e) {console.error(e.message)}

Детали

Я провожу следующие тесты для решений A B C DE (мой)

  • для небольшого массива (4 элемента) - вы можете запустить тест ЗДЕСЬ
  • для большого массива (1M элементов) - вы можете запустить тест ЗДЕСЬ

function A(arr, idx) {
  delete arr[idx];
  return arr;
}

function B(arr, idx) {
  arr.splice(idx,1);
  return arr;
}

function C(arr, idx) {
  var rest = arr.slice(idx + 1 || arr.length);
  arr.length = idx < 0 ? arr.length + idx : idx;
  arr.push.apply(arr, rest);
  return arr;
}

function D(arr,idx){
    return arr.slice(0,idx).concat(arr.slice(idx + 1));
}

function E(arr,idx) {
  return arr.filter((a,i) => i !== idx);
}

myArray = ['a', 'b', 'c', 'd'];

[A,B,C,D,E].map(f => console.log(`${f.name} ${JSON.stringify(f([...myArray],1))}`));
This snippet only presents used solutions

Примеры результатов для Chrome

Это разные вещи, которые имеют разные цели.

splice является специфичным для массива и, когда используется для удаления, удаляет записи из массива и перемещает все предыдущие записи вверх, чтобы заполнить пробел. (Он также может быть использован для вставки записей, или оба одновременно.) splice изменит length массива (при условии, что это не вызов no-op: theArray.splice(x, 0)).

delete не зависит от массива; он предназначен для использования на объектах: он удаляет свойство (пара ключ / значение) из объекта, на котором вы его используете. Это применимо только к массивам, потому что стандартные (например, нетипизированные) массивы в JavaScript вообще не являются массивами *, это объекты со специальной обработкой для определенных свойств, таких как те, чьи имена являются "индексами массива" (которые являются определяется как строковые имена "... чье числовое значение i находится в диапазоне +0 ≤ i < 2^32-1 ") а также length, Когда вы используете delete чтобы удалить запись массива, все, что он делает, - удаляет запись; он не перемещает другие записи, следующие за ним, чтобы заполнить пробел, и поэтому массив становится "разреженным" (некоторые записи полностью отсутствуют). Не влияет на length,

В паре текущих ответов на этот вопрос неправильно указано, что при использовании delete "устанавливает запись в undefined Msgstr "Это не правильно. Он полностью удаляет запись (свойство), оставляя пробел.

Давайте использовать некоторый код, чтобы проиллюстрировать различия:

console.log("Using `splice`:");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a.splice(0, 1);
console.log(a.length);            // 4
console.log(a[0]);                // "b"

console.log("Using `delete`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
delete a[0];
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // false
console.log(a.hasOwnProperty(0)); // false

console.log("Setting to `undefined`");
var a = ["a", "b", "c", "d", "e"];
console.log(a.length);            // 5
a[0] = undefined;
console.log(a.length);            // still 5
console.log(a[0]);                // undefined
console.log("0" in a);            // true
console.log(a.hasOwnProperty(0)); // true


* (это пост в моем маленьком анемичном блоге)

У меня есть два метода.

Простой:

      arr = arr.splice(index,1)

Второй:

      arr = arr.filter((v,i)=>i!==index)

Преимущество второго заключается в том, что вы можете удалить значение (все, а не только первый экземпляр, как большинство)

      arr = arr.filter((v,i)=>v!==value)

Почему не просто фильтр? Я думаю, что это самый понятный способ рассмотреть массивы в JS.

myArray = myArray.filter(function(item){
    return item.anProperty != whoShouldBeDeleted
});

Остальные уже как следует сравнивали delete с splice.

Еще одно интересное сравнение delete против undefined: удаленный элемент массива использует меньше памяти, чем тот, который только что установлен на undefined;

Например, этот код не завершится:

let y = 1;
let ary = [];
console.log("Fatal Error Coming Soon");
while (y < 4294967295)
{
    ary.push(y);
    ary[y] = undefined;
    y += 1;
}
console(ary.length);

Это вызывает эту ошибку:

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory.

Итак, как видите undefined на самом деле занимает кучу памяти.

Однако если вы также delete ary-item (вместо того, чтобы просто установить его на undefined), код медленно завершится:

let x = 1;
let ary = [];
console.log("This will take a while, but it will eventually finish successfully.");
while (x < 4294967295)
{
    ary.push(x);
    ary[x] = undefined;
    delete ary[x];
    x += 1;
}
console.log(`Success, array-length: ${ary.length}.`);

Это крайние примеры, но они подчеркивают delete что я нигде не видел, чтобы кто-то упоминал.

Если у вас небольшой массив, вы можете использовать filter:

myArray = ['a', 'b', 'c', 'd'];
myArray = myArray.filter(x => x !== 'b');

В настоящее время есть два способа сделать это

  1. используя splice()

    arrayObject.splice(index, 1);

  2. используя удалить

    delete arrayObject[index];

Но я всегда предлагаю использовать соединение для объектов массива и удалять для атрибутов объектов, потому что удаление не обновляет длину массива.

function remove_array_value(array, value) {
    var index = array.indexOf(value);
    if (index >= 0) {
        array.splice(index, 1);
        reindex_array(array);
    }
}
function reindex_array(array) {
   var result = [];
    for (var key in array) {
        result.push(array[key]);
    }
    return result;
}

пример:

var example_arr = ['apple', 'banana', 'lemon'];   // length = 3
remove_array_value(example_arr, 'banana');

банан удаляется и длина массива = 2

Будь проще :-

Когда вы удаляете любой элемент в массиве, он удалит значение упомянутой позиции и сделает его пустым/неопределенным, но позиция существует в массиве.

Хорошо, представьте, что у нас есть этот массив ниже:

const arr = [1, 2, 3, 4, 5];

Давайте сначала удалим:

delete arr[1];

и вот результат:

[1, empty, 3, 4, 5];

пусто! и давайте получим это:

arr[1]; //undefined

Значит, означает только удаленное значение, и оно теперь не определено, поэтому длина такая же, и она вернет true...

Давайте сбросим наш массив и на этот раз сделаем это со сращиванием:

arr.splice(1, 1);

и вот результат на этот раз:

[1, 3, 4, 5];

Как вы видите, длина массива изменилась и arr[1] сейчас 3...

Также это вернет удаленный элемент в массиве, который [3] в этом случае...

Самый простой способ, вероятно,

var myArray = ['a', 'b', 'c', 'd'];
delete myArray[1]; // ['a', undefined, 'c', 'd']. Then use lodash compact method to remove false, null, 0, "", undefined and NaN
myArray = _.compact(myArray); ['a', 'c', 'd'];

Надеюсь это поможет. Ссылка: https://lodash.com/docs

delete: delete удалит свойство объекта, но не переиндексирует массив или не обновит его длину. Это делает его похожим на неопределенное:

splice: фактически удаляет элемент, переиндексирует массив и изменяет его длину.

Удалить элемент из последнего

arrName.pop();

Удалить элемент из первого

arrName.shift();

Удалить из середины

arrName.splice(starting index,number of element you wnt to delete);

Ex: arrName.splice(1,1);

Удалить один элемент из последнего

arrName.splice(-1);

Удалить используя индексный номер массива

 delete arrName[1];

Если нужный элемент находится посередине (скажем, мы хотим удалить 'c', индекс которого равен 1):

var arr = ['a','b','c'];

Ты можешь использовать: var indexToDelete = 1; var newArray = arr.slice(0, indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))

IndexOf принимает также ссылочный тип. Предположим следующий сценарий:

var arr = [{item: 1}, {item: 2}, {item: 3}];

var found = find(2, 3); //pseudo code: will return [{item: 2}, {item:3}]

var l = found.length;
while(l--) {
  var index = arr.indexOf(found[l])
  arr.splice(index, 1);
}

console.log(arr.length); //1

По-другому:

var item2 = findUnique(2); //will return {item: 2}
var l = arr.length;
var found = false;
  while(!found && l--) {
  found = arr[l] === item2;
}

console.log(l, arr[l]);// l is index, arr[l] is the item you look for

Для тех, кто хочет использовать Lodash, можно использовать:myArray = _.without(myArray, itemToRemove)

Или как я использую в Angular2

import { without } from 'lodash';
...
myArray = without(myArray, itemToRemove);
...
function deleteFromArray(array, indexToDelete){
  var remain = new Array();
  for(var i in array){
    if(array[i] == indexToDelete){
      continue;
    }
    remain.push(array[i]);
  }
  return remain;
}

myArray = ['a', 'b', 'c', 'd'];
deleteFromArray(myArray , 0);

// результат: myArray = ['b', 'c', 'd'];

Другие вопросы по тегам