Видалення елементів масиву в JavaScript - видалити vs сплайс


1333

У чому різниця між використанням в deleteоператор на елементі масиву на відміну від використання в Array.spliceметод ?

Наприклад:

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

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

Навіщо навіть використовувати метод сплайсингу, якщо я можу видалити елементи масиву, як я можу, з об’єктами?


3
Для .spliceциклів перегляньте це питання: Видалити з масиву в JavaScript .
Rob W

6
@andynormancx Так, але ця відповідь була опублікована лише на наступний день, і я отримав так багато голосів - я б сказав, що це краще написано, так і повинно бути.
Каміло Мартін

@andynormancx - Це, здається, не є точним дублікатом. Питання, з яким ви пов’язали, в основному задає, чому видалення елемента з масиву (таким чином робить його рідким) не зменшить його довжину. Це питання задає відмінності між deleteта Array.prototype.splice.
chharvey

@chharvey погодився, що ще важливіше, але як це питання можна було опублікувати 9 років тому! Змушує мене відчувати себе старим тут, коментуючи це
andynormancx

Відповіді:


1692

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"]

74
Насправді, delete він видаляє елемент, але не перенастроює масив і не оновлює його довжину (що вже має на увазі попередній, оскільки довжина завжди є найвищим показником + 1).
Фелікс Клінг

3
JSlint не любить delete myArray[0]синтаксис із записом " Очікується, що оператор і замість цього побачив" видалити ". Використання spliceрекомендується.
Очі

21
@Eye: Насправді JSLint просто скаржиться на відсутність крапки з комою в попередньому рядку. І ви не можете реально рекомендувати одне за одним, оскільки вони роблять зовсім інші речі ...
Ry-

3
"Видалити в цьому випадку елемент буде встановлено лише як невизначений:" Ні, це абсолютно неправильно. Існує принципова різниця між delete myArray[0]та myArray[0] = undefined. У першому випадку властивість видаляється з об’єкта масиву повністю. У другому випадку властивість залишається зі значенням undefined.
TJ Crowder

1
FYI, інструменти для розробників Chrome показують ключове слово emptyзамість того, undefinedщоб поліпшити відмінність між фактично видаленим (або неініціалізованим) елементом масиву проти елемента, який має реальне значення undefined. Зауважте, що, як я це кажу, я маю на увазі, що воно відображається лише як emptyі не посилається на реальне значення, яке називається empty(яке не існує).
chharvey

340

Метод 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);

Веб-сайт Джона


4
+1 Для Array.remove (). Однак передавати строкові аргументи не радий (на відміну від більшості методів Array, наприклад [1,2,3].slice('1'); // =[2,3]), тому безпечніше змінити його наvar rest = this.slice(parseInt(to || from) + 1 || this.length);
Річард Інгліс

1
@tomwrong, в JavaScript немає ниток, і функція виконує this.push.apply(this, rest), потім повертає значення, яке воно повернуло
billy

59
Це зовсім не відповідає на питання.
Ри-

16
Чому б не просто використовувати splice ()? Назва цієї функції, назви параметрів та результати не очевидні. Моя рекомендація - просто використовувати сплайс (індекс, довжина) - (див. Відповідь Енді Юма)
auco

3
Наведена вище функція працює як пояснено, але вона створює небажані побічні ефекти при ітерації через масив for(var i in array)циклом. Я його видалив і використав замість нього сплайс.
alexykot

104

Оскільки видалення видаляє лише об'єкт з елемента в масиві, довжина масиву не зміниться. Сплайс видаляє об'єкт і скорочує масив.

У наступному коді відображатимуться "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]);
}

11
чудовий приклад за винятком неоднозначності у другому прикладі з використанням 1,1 - перший 1 відноситься до індексу в масиві для запуску сплайсу, другий 1 - кількість елементів, які потрібно видалити. Отже, щоб видалити 'c' з початкового масиву, використовуйтеmyArray.splice(2,1)
iancoleman

68

Я натрапив на це питання, намагаючись зрозуміти, як видалити кожне виникнення елемента з масиву. Ось порівняння з 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"]

14

З Core JavaScript 1.5 Посилання> Оператори> Спеціальні оператори> видалити Оператора :

Коли ви видаляєте елемент масиву, на довжину масиву не впливає. Наприклад, якщо ви видалите [3], a [4] все ще є [4], а [3] не визначено. Це справедливо, навіть якщо ви видалите останній елемент масиву (видаліть [a.length-1]).


10

splice буде працювати з числовими показниками.

враховуючи, що deleteїх можна використовувати проти інших видів індексів ..

приклад:

delete myArray['text1'];

9
Коли ви говорите "будь-який інший тип індексів", ви вже не говорите про масиви, а про об'єкти, про що запитує ОП.
Yi Jiang

2
@YiJiang: Масиви - це об'єкти. Вказує - це властивості. Різниці немає.
Бергі

9

Напевно, варто також згадати, що сплайс працює лише на масивах. (Не можна покладатися на властивості об'єкта, щоб дотримуватися послідовного порядку.)

Щоб видалити пару об’єктів ключ-значення з об'єкта, видалити насправді те, що ви хочете:

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

delete не впорядковує ключі масиву, тому: var arr = [1,2,3,4,5]; видалити arr [3]; for (var i = 0; i <= arr.length; i ++) console.log (arr [i]); покаже несподівані результати.
Крістіан Вільямс

Це правда. Тому, якщо ви не хочете залишити невизначений елемент у цьому місці, НЕ використовуйте delete на клавішах масиву! Я спочатку додав цей коментар, щоб включити посилання на правильне використання видалення.
jtrick

але чому видалення кине несподіваний результат ??
Олексій

9

видалити Vs зрощення

коли ви видаляєте елемент з масиву

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

коли ви зрощуєте

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

в разі видалення елемента видаляється , але індекс залишається порожнім

в той час як у випадку з’єднання елемент видаляється, а індекс елементів відпочинку відповідно зменшується


8

Як було сказано багато разів вище, використання 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()вилучіть лише елементи з масиву.

Повернене значення

Масив, що містить вилучені елементи. Якщо видалено лише один елемент, повертається масив одного елемента. Якщо жодні елементи не видалені, повертається порожній масив.

[...]


@downvoter: чому downvote? хочете пояснити, чи ні?
серв-інк

7

видалення діє як нереальна ситуація, вона просто видаляє елемент, але довжина масиву залишається такою ж:

Приклад з терміналу вузла:

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

Ось функція для видалення елемента масиву за індексом, використовуючи фрагмент () , він приймає 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

зауважте, що це не буде працювати з одним масивом з dupes в ньому, тому що indexOf ("c") просто отримає перше значення, і лише зробіть зріз і видаліть перший "c", який він знайде.


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)
},

Я вважаю, індекс ++; має відбуватися поза "якщо". Внесення
змін

6

ви можете використовувати щось подібне

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]


це більш інтуїтивно зрозуміло, ніж sliceякщо ви походите з функціонального фону (хоча, мабуть, менш ефективно).
jetro

3

Чому б не просто фільтрувати? Я думаю, що це найбільш зрозумілий спосіб розглянути масиви в js.

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

А що з масивом із сотнями (якщо не тисячами) записів, з яких потрібно видалити лише 3?
Джоель Ернандес

гарна думка. Я використовую цей метод для розріджених масивів, довжина яких не перевищує 200 або 300 і виконує дуже добре. Однак, я думаю, бібліотеки, як підкреслення, слід віддавати перевагу, якщо вам доведеться керувати такими більшими масивами.
Аскан

1
Однак мені здається набагато приємніше, ніж мені deleteабо slice.
Juneyoung О

3

Різницю можна побачити, записуючи довжину кожного масиву після застосування 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.


2
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


2

Вони різні речі, які мають різні цілі.

spliceє специфічним для масиву і, коли використовується для видалення, видаляє записи з масиву і переміщує всі попередні записи вгору, щоб заповнити пробіл. (Він також може бути використаний для вставки записів, або обох одночасно.) spliceЗмінить lengthмасив (припускаючи, що це не неоперативний виклик:) theArray.splice(x, 0).

deleteне є специфічним для масиву; він призначений для використання на об'єктах: він видаляє властивість (пару ключів / значень) з об'єкта, на якому ви його використовуєте. Це стосується лише масивів, оскільки стандартні (наприклад, нетипізовані) масиви в JavaScript насправді зовсім не є масивами *, це об'єкти зі спеціальними обробками для певних властивостей, наприклад, ті, назви яких "індекси масивів" (які є визначено як імена рядків "... числове значення яких iзнаходиться в діапазоні +0 ≤ i < 2^32-1") і length. Коли ви використовуєте deleteдля видалення запису масиву, все, що він робить, - це видалити запис; він не переміщує інші записи за ним, щоб заповнити прогалину, і таким чином масив стає «розрідженим» (деякі записи повністю відсутні). Це не впливає на length.

Кілька нинішніх відповідей на це питання неправильно стверджують, що за допомогою delete"встановлює запис undefined". Це не правильно. Він повністю видаляє запис (властивість), залишаючи пробіл.

Давайте скористаємось кодом для ілюстрації відмінностей:

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


* (це допис у моєму анемічному маленькому блозі)


2

В даний час існує два способи зробити це

  1. за допомогою сплайсу ()

    arrayObject.splice(index, 1);

  2. за допомогою видалення

    delete arrayObject[index];

Але я завжди пропоную використовувати сплайсинг для об’єктів масиву та видаляти для атрибутів об’єктів, оскільки видалення не оновлює довжину масиву.


1

Гаразд, уявіть, що ми маємо цей масив нижче:

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

Давайте спочатку видалимо:

delete arr[1];

і це результат:

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

порожній! і давайте це:

arr[1]; //undefined

Отже, означає просто видалене значення, і воно зараз не визначене , тому довжина така ж, і вона поверне справжню ...

Давайте скинемо наш масив і зробимо це зі сплайсом на цей раз:

arr.splice(1, 1);

і це результат цього разу:

[1, 3, 4, 5];

Як ви бачите, довжина масиву змінилася і arr[1]становить 3 зараз ...

Також це поверне видалений елемент у масиві, який [3]у цьому випадку ...


1

Інші вже правильно порівняли 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архів-елемент (замість того, щоб просто встановити його 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те, що я ніде не бачив, щоб хтось згадував.


1

Якщо у вас є невеликий масив, ви можете використовувати filter:

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

0

Найпростіший спосіб - це, мабуть

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#compact


1
Якщо хтось наткнеться на це питання compact... не потрібно лодаш. СпробуйтеmyArray.filter(function(n){return n;})
дат

0

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

Або як я використовую в Angular2

import { without } from 'lodash';
...
myArray = without(myArray, itemToRemove);
...

0

delete : delete видалить властивість об'єкта, але не переробить масив або оновить його довжину. Через це видається так, ніби це не визначено:

сплайс : фактично видаляє елемент, повторно дексесує масив та змінює його довжину.

Видалити елемент з останнього

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];

0

Якщо потрібний елемент для видалення знаходиться посередині (скажімо, ми хочемо видалити 'c', індекс якого дорівнює 1), ви можете використовувати:

var arr = ['a','b','c'];
var indexToDelete = 1;
var newArray = arr.slice(0,indexToDelete).combine(arr.slice(indexToDelete+1, arr.length))

0

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

-1
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'];


@ChrisDennis чому? (ніякого сарказму чи злоби не передбачається, це щире питання)
Кріс Бір

Окрім того, що ця відповідь не стосується питання ОП
Кріс Бір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.