Як я можу видалити конкретний елемент із масиву?


8284

У мене є масив чисел і я використовую .push()метод для додавання до нього елементів.

Чи є простий спосіб видалити певний елемент із масиву?

Я шукаю еквівалент чогось типу:

array.remove(number);

Я повинен використовувати основний JavaScript. Кадри не дозволені.

Відповіді:


11875

Знайдіть indexелемент масиву, який ви хочете видалити indexOf, та видаліть цей індекс за допомогою splice.

Метод splice () змінює вміст масиву, видаляючи існуючі елементи та / або додаючи нові елементи.

const array = [2, 5, 9];

console.log(array);

const index = array.indexOf(5);
if (index > -1) {
  array.splice(index, 1);
}

// array = [2, 9]
console.log(array); 

Другий параметр splice- кількість елементів, які потрібно видалити. Зверніть увагу, що spliceмодифікує масив на місці і повертає новий масив, що містить елементи, які були видалені.


З метою повноти ось функції. Перша функція видаляє лише один випадок (тобто видалення першого збігу 5з [2,5,9,1,5,8,5]), а друга функція видаляє всі події:

function removeItemOnce(arr, value) { 
    var index = arr.indexOf(value);
    if (index > -1) {
        arr.splice(index, 1);
    }
    return arr;
}

function removeItemAll(arr, value) {
    var i = 0;
    while (i < arr.length) {
        if(arr[i] === value) {
            arr.splice(i, 1);
        } else {
            ++i;
        }
    }
    return arr;
}

15
@ Петер, так, ти можеш мати рацію. Ця стаття пояснює більше і містить вирішення невідповідних веб-переглядачів: developer.mozilla.org/uk/JavaScript/Reference/Global_Objects/…
Том Уодлі,

33
@AlexandreWiechersVaz Звичайно, він зберігає порядок, якщо б цього не було, це було б абсолютно нікчемно
TheZ

15
Ви можете подолати проблему з підтримкою браузера IE, включивши вказаний тут

15
@AdrianP. array.indexOf(testValue)на порожньому масиві буде -1, а якщо ви тестуєте на це, то ніякого зрощення. Можливо, відповідь змінилася з тих пір.
UpTheCreek

13
IE 7, IE8, IE9, IE10 не підтримується самим Microsoft, чому веб-розробники повинні підтримувати ці старі браузери? Просто покажіть сповіщення про оновлення браузера! support.microsoft.com/en-us/lifecycle/…
Лукас Лієсіс

1263

Я не знаю, як ви розраховуєте array.remove(int)вести себе. Є три можливості, які я можу придумати, що ви можете хотіти.

Щоб видалити елемент масиву в індексі i:

array.splice(i, 1);

Якщо ви хочете видалити кожен елемент зі значенням numberз масиву:

for(var i = array.length - 1; i >= 0; i--) {
    if(array[i] === number) {
        array.splice(i, 1);
    }
}

Якщо ви просто хочете, щоб елемент в індексі iбільше не існував, але ви не хочете, щоб індекси інших елементів змінювалися:

delete array[i];

333
deleteце не правильний спосіб видалення елемента з масиву!
Фелікс Клінг

71
@FelixKling Це залежить, він працює, якщо ви хочете зробити так, щоб array.hasOwnProperty(i)повертався falseі елемент у цій позиції повертався undefined. Але я визнаю, що це не дуже звичайна річ, яку хочеться робити.
Пітер Олсон

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

34
@diosney Я не знаю, що ти маєш на увазі, коли ти кажеш, що це дійсно не стирає елемент. Крім того, він робить більше, ніж просто замінює значення в цьому індексі на undefined: він видаляє і індекс, і значення з масиву, тобто після delete array[0], "0" in arrayповерне помилковим.
Пітер Олсон

17
@GrantGryczan Вибачте, я не згоден. Я не бачу необхідності цього видаляти. У наведеному вище тексті чітко пояснюється, що він робить, і він допомагає людям, які не знають, що deleteробити, зрозуміти, чому це не працює, як вони очікують.
Пітер Олсон

1203

Відредаговано 2016 жовтня

  • Робіть це просто, інтуїтивно та зрозуміло ( бритви Оккама )
  • Зробити це незмінним (оригінальний масив залишається незмінним)
  • Робіть це за допомогою стандартних функцій JavaScript, якщо ваш браузер їх не підтримує - використовуйте polyfill

У цьому прикладі коду я використовую функцію "array.filter (...)" для видалення небажаних елементів з масиву. Ця функція не змінює вихідний масив і створює новий. Якщо ваш веб-переглядач не підтримує цю функцію (наприклад, Internet Explorer перед версією 9, або Firefox до версії 1.5), спробуйте скористатися поліфільтруванням від Mozilla .

Видалення елемента (код ECMA-262 видання 5, також aka oldstyle JavaScript)

var value = 3

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

arr = arr.filter(function(item) {
    return item !== value
})

console.log(arr)
// [ 1, 2, 4, 5 ]

Видалення елемента (код ECMAScript 6)

let value = 3

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => item !== value)

console.log(arr)
// [ 1, 2, 4, 5 ]

ВАЖЛИВО Синтаксис функції стрілки ECMAScript 6 "() => {}" не підтримується в Internet Explorer, Chrome до 45 версії, Firefox до 22 версії та Safari до 10 версії. Для використання синтаксису ECMAScript 6 у старих браузерах ви можете використовувати BabelJS .


Видалення кількох елементів (код ECMAScript 7)

Додатковою перевагою цього методу є те, що ви можете видалити кілька предметів

let forDeletion = [2, 3, 5]

let arr = [1, 2, 3, 4, 5, 3]

arr = arr.filter(item => !forDeletion.includes(item))
// !!! Read below about array.includes(...) support !!!

console.log(arr)
// [ 1, 4 ]

ВАЖЛИВО функція "array.includes (...)" взагалі не підтримується в Internet Explorer, Chrome до 47-ї версії, Firefox до 43-ї версії, Safari до версії 9 та Edge до 14- ї версії, тому тут є поліфайл від Mozilla .

Видалення кількох елементів (можливо, у майбутньому)

Якщо пропозиція "Синтаксис цього прив'язування" буде прийнята, ви зможете зробити це:

// array-lib.js

export function remove(...forDeletion) {
    return this.filter(item => !forDeletion.includes(item))
}

// main.js

import { remove } from './array-lib.js'

let arr = [1, 2, 3, 4, 5, 3]

// :: This-Binding Syntax Proposal
// using "remove" function as "virtual method"
// without extending Array.prototype
arr = arr::remove(2, 3, 5)

console.log(arr)
// [ 1, 4 ]

Спробуйте самі в BabelJS :)

Довідково


6
але, іноді ми хочемо видалити елемент з початкового масиву (незмінний), наприклад масив, який використовується у Angular 2 * ngДо директиви
Ravinder Payal

43
Краще, ніж прийняте рішення, оскільки воно не передбачає лише однієї зустрічі, а незмінність є кращою
Грег,

13
filterДля великого масиву має бути набагато повільніше?
Натан

3
Який сенс незмінності згадується, якщо ви використовували присвоєння тієї ж змінної у своїх прикладах? :)
mench

12
Це чудова відповідь. Сплайс - спеціалізована функція для мутації, що не фільтрує. filterможе мати меншу продуктивність, але це безпечніший і кращий код. Крім того, ви можете фільтрувати за індексом, вказавши другий аргумент в лямбда:arr.filter((x,i)=>i!==2)
Матвій

449

Це залежить від того, хочете ви зберегти порожнє місце чи ні.

Якщо ви хочете порожній слот, видалення добре:

delete array[index];

Якщо цього немає, слід скористатися методом зрощення :

array.splice(index, 1);

І якщо вам потрібне значення цього елемента, ви можете просто зберігати повернутий елемент масиву:

var value = array.splice(index, 1)[0];

Якщо ви хочете зробити це в якомусь порядку, ви можете використовувати array.pop()для останнього або array.shift()для першого (і обидва повертають значення елемента).

І якщо ви не знаєте індексу товару, ви можете використовувати його array.indexOf(item)для отримання (в, if()щоб отримати один предмет або в а, while()щоб отримати їх усі). array.indexOf(item)повертає або індекс, або -1, якщо його не знайдено. 


25
deleteце не правильний спосіб видалення елемента з масиву !!
Прого

16
Якщо ви хочете "спорожнити слот", використовуйте array[index] = undefined;. Використання deleteзнищить оптимізацію.
Бергі

4
@Jakub дуже хороший коментар, тому що, щоб зрозуміти, що я втратив багато часу і подумав, що мій код програми якось порушений ...
Паскаль

Останній абзац з поясненням того, що ви отримуєте від indexOf, був дуже корисним
A. D'Alfonso

277

У друга виникли проблеми в Internet Explorer 8 і показав мені, що він робив. Я сказав йому, що це неправильно, і він сказав мені, що отримав відповідь тут. Поточна відповідь не буде працювати у всіх веб-переглядачах (наприклад, Internet Explorer 8), і вона видалить лише перший елемент цього пункту.

Видаліть ВСІ екземпляри з масиву

function remove(arr, item) {
    for (var i = arr.length; i--;) {
        if (arr[i] === item) {
            arr.splice(i, 1);
        }
    }
}

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


11
@sroes цього не повинно бути, тому що цикл починається з i = arr.length -1або i--робить його таким же, як максимальний індекс. arr.length- лише початкове значення для i. i--завжди буде правдою (і зменшується на 1 у кожному циклі), поки вона не дорівнює 0(хибне значення), і цикл потім припиниться.
gmajivu

1
Друга функція є досить неефективною. На кожній ітерації "indexOf" почне пошук з початку масиву.
ujeenator

3
@AmberdeBlack, у колекції, що містить більше одного елемента , набагато краще замість цього викликати метод фільтраarr.filter(function (el) { return el !== item }) , уникаючи необхідності мутувати масив кілька разів. Це витрачає трохи більше пам’яті, але працює набагато ефективніше, оскільки там менше роботи, яку потрібно виконати.
Євген Кузьменко

1
@AlJey, він доступний лише з IE9 +. Є ще ймовірність, що це не спрацює.
ujeenator

1
Ця відповідь спрацювала для мене, бо мені було потрібно вилучити кілька предметів, але не в якомусь конкретному порядку. Зворотне просування циклу for тут ідеально обробляє видалення елементів з масиву.
чеканий

172

Є два основні підходи:

  1. сплайс () :anArray.splice(index, 1);

  2. видалити :delete anArray[index];

Будьте обережні, використовуючи delete для масиву. Це добре для видалення атрибутів об’єктів, але не так добре для масивів. Краще використовувати spliceдля масивів.

Майте на увазі, що, використовуючи deleteмасив, ви можете отримати неправильні результати anArray.length. Іншими словами, deleteбуде видалено елемент, але він не оновлює значення властивості length.

Ви також можете очікувати наявності отворів у номерах індексів після використання видалення, наприклад, ви можете мати індекси 1, 3, 4, 8, 9 та 11 та довжину, як це було до використання видалення. У такому випадку всі індексовані forцикли зазнають краху, оскільки індекси вже не є послідовними.

Якщо ви змушені користуватися deleteз якихось причин, то вам слід використовувати for eachпетлі, коли вам потрібно прокрутити масиви. Власне, завжди уникайте використання індексованих forциклів, якщо це можливо. Таким чином код був би більш надійним і менш схильним до проблем з індексами.


144
Array.prototype.remByVal = function(val) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] === val) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
}
//Call like
[1, 2, 3, 4].remByVal(3);

Array.prototype.remByVal = function(val) {
    for (var i = 0; i < this.length; i++) {
        if (this[i] === val) {
            this.splice(i, 1);
            i--;
        }
    }
    return this;
}

var rooms = ['hello', 'something']

rooms = rooms.remByVal('hello')

console.log(rooms)


14
Я не є великим прихильником такого підходу. Якщо ви користуєтесь різними бібліотеками чи рамками, вони можуть конфліктувати між собою.
Чарлі Кіліан

10
Погана ідея, побачити цей пост: stackoverflow.com/questions/948358/array-prototype-problem
MMeah

10
Якщо ви займаєтеся for inмасивом, у вас вже є проблема.
Зірак

2
якщо ви робите for inна масивах, у вас вже є більші проблеми.
Дощ

використовуйте Object.defineProperty stackoverflow.com/a/35518127/3779853, і ви готові йти.
phil294

105

Не потрібно використовувати indexOfабо splice. Однак вона працює краще, якщо ви хочете видалити лише одне виникнення елемента.

Пошук і переміщення (переміщення):

function move(arr, val) {
  var j = 0;
  for (var i = 0, l = arr.length; i < l; i++) {
    if (arr[i] !== val) {
      arr[j++] = arr[i];
    }
  }
  arr.length = j;
}

Використання indexOfта splice(indexof):

function indexof(arr, val) {
  var i;
  while ((i = arr.indexOf(val)) != -1) {
    arr.splice(i, 1);
  }
}

Використовуйте лише splice(зрощення):

function splice(arr, val) {
  for (var i = arr.length; i--;) {
    if (arr[i] === val) {
      arr.splice(i, 1);
    }
  }
}

Часи запуску на nodejs для масиву з 1000 елементами (в середньому понад 10000 запусків):

indexof приблизно в 10 разів повільніше, ніж переміщення . Навіть якщо вдосконалено, видаливши виклик indexOfв сплайс, він виконує набагато гірше, ніж переміщення .

Remove all occurrences:
    move 0.0048 ms
    indexof 0.0463 ms
    splice 0.0359 ms

Remove first occurrence:
    move_one 0.0041 ms
    indexof_one 0.0021 ms

5
Схоже, представлений тут метод "переміщення" повинен працювати у всіх браузерах, а також уникає створення додаткового масиву; Більшість інших рішень тут мають одну або обидві ці проблеми. Я думаю, що цей заслуговує на набагато більше голосів, навіть якщо він не виглядає як "симпатичний".
sockmonk

73

Це забезпечує присудок замість значення.

ПРИМІТКА: він оновить заданий масив і поверне постраждалі рядки.

Використання

var removed = helper.removeOne(arr, row => row.id === 5 );

var removed = helper.remove(arr, row => row.name.startsWith('BMW'));

Визначення

var helper = {

    // Remove and return the first occurrence

    removeOne: function(array, predicate) {
        for (var i = 0; i < array.length; i++) {
            if (predicate(array[i])) {
                return array.splice(i, 1);
            }
        }
    },

    // Remove and return all occurrences

    remove: function(array, predicate) {
        var removed = [];

        for (var i = 0; i < array.length;) {

            if (predicate(array[i])) {
                removed.push(array.splice(i, 1));
                continue;
            }
            i++;
        }
        return removed;
    }
};

Я не знаю, що вам потрібен чек -1 (i> -1). Крім того, я думаю, що ці функції більше нагадують фільтр, ніж видаляти. Якщо ви передасте row.id === 5, це призведе до масиву з лише id 5, тому він видаляє протилежне видаленню. Це буде добре виглядати в ES2015: var result = ArrayHelper.remove (myArray, row => row.id === 5);
Що було б круто

@WhatWouldBeCool ця функція модифікує вихідний масив і повертає вилучений елемент замість того, щоб скопіювати результат у новий масив
amd

68

Ви можете легко це зробити методом фільтра :

function remove(arrOriginal, elementToRemove){
    return arrOriginal.filter(function(el){return el !== elementToRemove});
}
console.log(remove([1, 2, 1, 0, 3, 1, 4], 1));

Це видаляє всі елементи з масиву, а також працює швидше, ніж комбінація sliceта indexOf.


3
Чи є у вас джерело, що це швидше?
користувач3711421

2
Приємне рішення. Але як ви зазначаєте, але важливо зробити лисий, він не дає такого ж результату, як зріз та indexOf, оскільки він видалить усі випадки 1
user3711421

1
@ user3711421 це тому, що просто фрагмент і indexOf не роблять того, що він хоче, "щоб видалити певний елемент". Цей елемент видаляється лише один раз, при цьому видаляйте конкретний елемент незалежно від того, скільки у вас є
Сальвадор Далі

66

Джон Резиг виклав хорошу реалізацію :

// 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);
};

Якщо ви не хочете розширювати глобальний об’єкт, натомість можете зробити щось подібне:

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

Але головна причина, яку я публікую, - це застерегти користувачів від альтернативної реалізації, запропонованої в коментарях на цій сторінці (14 грудня 2007 р.):

Array.prototype.remove = function(from, to){
  this.splice(from, (to=[0,from||1,++to-from][arguments.length])<0?this.length+to:to);
  return this.length;
};

Спочатку, здається, працює добре, але через болісний процес я виявив, що це не вдається при спробі видалити другий до останнього елемента з масиву. Наприклад, якщо у вас є 10-елементний масив і ви намагаєтесь видалити 9-й елемент за допомогою цього:

myArray.remove(8);

Ви закінчуєте 8-елементний масив. Не знаю чому, але я підтвердив, що в оригінальній реалізації Джона немає цієї проблеми.


Щойно навчився важким способом, чому це гарна ідея використовувати Object.prototype.hasOwnPropertyзавжди
¬¬

64

Underscore.js можна використовувати для вирішення проблем із кількома браузерами. Він використовує вбудовані методи браузера, якщо вони є. Якщо вони відсутні, як у випадку з більш старими версіями Internet Explorer, він використовує свої власні методи.

Простий приклад для видалення елементів з масиву (з веб-сайту):

_.without([1, 2, 1, 0, 3, 1, 4], 0, 1); // => [2, 3, 4]

хоч елегантний та стислий, OP чітко згадував лише основний JS
EigenFool

64

Можна використовувати ES6. Наприклад, щоб видалити значення "3" у цьому випадку:

var array=['1','2','3','4','5','6']
var newArray = array.filter((value)=>value!='3');
console.log(newArray);

Вихід:

["1", "2", "4", "5", "6"]

4
Ця відповідь хороша тим, що створює копію оригінального масиву, а не змінює оригінал безпосередньо.
Клаудіо Голландія

Примітка: Array.prototype.filter - це ECMAScript 5.1 (немає IE8). більш конкретні рішення: stackoverflow.com/a/54390552/8958729
Чанг

54

Якщо ви хочете, щоб новий масив із видаленими позиціями був видалений, ви завжди можете видалити конкретний елемент і відфільтрувати масив. Може знадобитися розширення об’єкта масиву для браузерів, які не реалізують метод фільтра, але в перспективі це простіше, оскільки все, що ви робите, це:

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


45

Перевірте цей код. Він працює у кожному великому браузері .

remove_item = function (arr, value) {
    var b = '';
    for (b in arr) {
        if (arr[b] === value) {
            arr.splice(b, 1);
            break;
        }
    }
    return arr;
}

Викличте цю функцію

remove_item(array,value);

4
@RolandIllig За винятком використання for in-loop та того, що скрипт міг зупинятися раніше, безпосередньо повертаючи результат із циклу. Оновлення є розумними;)
yckart

1
Це відмінний підхід для малих масивів. Він працює у кожному браузері, використовує мінімальний та інтуїтивно зрозумілий код та без зайвих складних фреймворків, прокладки чи полів.
Beejor

Я також ще раз зазначу коментар yckart, що for( i = 0; i < arr.length; i++ )був би кращим підходом, оскільки він зберігає точні показники порівняно з будь-яким порядком, за яким браузер вирішить зберігати елементи (з for in). Це також дозволяє отримати індекс масиву значення, якщо він вам потрібен.
Beejor

41

Ви можете використовувати lodash _.pull (мутаційний масив), _.pullAt (мутаційний масив) або _.without (не мутує масив),

var array1 = ['a', 'b', 'c', 'd']
_.pull(array1, 'c')
console.log(array1) // ['a', 'b', 'd']

var array2 = ['e', 'f', 'g', 'h']
_.pullAt(array2, 0)
console.log(array2) // ['f', 'g', 'h']

var array3 = ['i', 'j', 'k', 'l']
var newArray = _.without(array3, 'i') // ['j', 'k', 'l']
console.log(array3) // ['i', 'j', 'k', 'l']

2
Це не основний JS, як просив ОП, чи не так?
не описує опис,

12
@ якийсь не описуючий користувач Ви маєте рацію. Але багато таких користувачів, як я, приїжджають сюди, шукаючи загальну відповідь не лише для ОП.
Чжун Ян

@ChunYang Ви абсолютно праві. Я вже використовую лодаш, чому б просто не використовувати його, якщо це економить час.
int-i

38

ES6 та без мутації: (жовтень 2016)

const removeByIndex = (list, index) =>
      [
        ...list.slice(0, index),
        ...list.slice(index + 1)
      ];
         
output = removeByIndex([33,22,11,44],1) //=> [33,11,44]
      
console.log(output)


Чому б просто не використовувати filterтоді? array.filter((_, index) => index !== removedIndex);.
користувач4642212

@ user4642212 ви праві! також мені сподобалось підкреслення голанг-стилю
Abdennour TOUMI

36

Видалення конкретного елемента / рядка з масиву можна виконати в одній вкладиші:

theArray.splice(theArray.indexOf("stringToRemoveFromArray"), 1);

де:

theArray : масив, з якого потрібно видалити щось конкретне

stringToRemoveFromArray : рядок, який потрібно видалити, і 1 - кількість елементів, які ви хочете видалити.

ПРИМІТКА : Якщо "stringToRemoveFromArray" не знаходиться у вашому масиві, це видалить останній елемент масиву.

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

if (theArray.indexOf("stringToRemoveFromArray") >= 0){
   theArray.splice(theArray.indexOf("stringToRemoveFromArray"), 1);
}

Якщо у вас є доступ до новіших версій Ecmascript на комп'ютерах вашого клієнта (ПОПЕРЕДЖЕННЯ, можливо, не працює на старих станціях):

var array=['1','2','3','4','5','6']
var newArray = array.filter((value)=>value!='3');

Де '3' - це значення, яке ви хочете видалити з масиву. Потім масив стане:['1','2','4','5','6']


Це відповідь, яка працювала для мене при спробі оновлення масиву на основі перемикання радіо кнопок.
jdavid05

4
Остерігайтеся, якщо "stringToRemoveFromArray"ваш масив не знаходиться, це видалить останній елемент масиву.
Fusion

35

Ось кілька способів видалення елемента з масиву за допомогою JavaScript .

Весь описаний метод не мутують вихідний масив , а натомість створюють новий.

Якщо ви знаєте індекс елемента

Припустимо, у вас є масив, і ви хочете прибрати елемент у своє місце i .

Одним із методів є використання slice():

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const i = 3
const filteredItems = items.slice(0, i).concat(items.slice(i+1, items.length))

console.log(filteredItems)

slice()створює новий масив з отриманими ним індексами. Ми просто створюємо новий масив, починаючи з індексу, який ми хочемо видалити, і об'єднуємо інший масив з першої позиції, наступної за тією, яку ми видалили, до кінця масиву.

Якщо ви знаєте значення

У цьому випадку можна використовувати один хороший варіант filter(), який пропонує декларативніший підхід:

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const valueToRemove = 'c'
const filteredItems = items.filter(item => item !== valueToRemove)

console.log(filteredItems)

Для цього використовуються функції стрілки ES6. Ви можете використовувати традиційні функції для підтримки старих браузерів:

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const valueToRemove = 'c'
const filteredItems = items.filter(function(item) {
  return item !== valueToRemove
})

console.log(filteredItems)

або ви можете скористатися Babel і перенести код ES6 назад в ES5, щоб зробити його більш засвоюваним для старих веб-переглядачів, але введіть сучасний JavaScript у свій код.

Видалення кількох елементів

Що робити, якщо замість одного елемента потрібно видалити багато предметів?

Давайте знайдемо найпростіше рішення.

За індексом

Ви можете просто створити функцію та видалити елементи послідовно:

const items = ['a', 'b', 'c', 'd', 'e', 'f']

const removeItem = (items, i) =>
  items.slice(0, i-1).concat(items.slice(i, items.length))

let filteredItems = removeItem(items, 3)
filteredItems = removeItem(filteredItems, 5)
//["a", "b", "c", "d"]

console.log(filteredItems)

За значенням

Ви можете шукати включення всередині функції зворотного дзвінка:

const items = ['a', 'b', 'c', 'd', 'e', 'f']
const valuesToRemove = ['c', 'd']
const filteredItems = items.filter(item => !valuesToRemove.includes(item))
// ["a", "b", "e", "f"]

console.log(filteredItems)

Уникайте мутування вихідного масиву

splice()(не плутати з slice()) мутує вихідний масив, і цього слід уникати.

(спочатку розміщено на веб- сайті https://flaviocopes.com/how-to-remove-item-from-array/ )


34

Добре, наприклад, у вас є масив нижче:

var num = [1, 2, 3, 4, 5];

І ми хочемо видалити номер 4. Ви можете просто скористатися наведеним нижче кодом:

num.splice(num.indexOf(4), 1); // num will be [1, 2, 3, 5];

Якщо ви повторно використовуєте цю функцію, ви пишете функцію багаторазового використання, яка буде приєднана до функції нативного масиву, як нижче:

Array.prototype.remove = Array.prototype.remove || function(x) {
  const i = this.indexOf(x);
  if(i===-1)
      return;
  this.splice(i, 1); // num.remove(5) === [1, 2, 3];
}

Але як бути, якщо у вас є масив нижче, а з кількома [5] с у масиві?

var num = [5, 6, 5, 4, 5, 1, 5];

Нам потрібна петля, щоб перевірити їх усі, але простішим та ефективнішим способом є використання вбудованих функцій JavaScript, тому ми пишемо функцію, яка замість цього використовує фільтр:

const _removeValue = (arr, x) => arr.filter(n => n!==x);
//_removeValue([1, 2, 3, 4, 5, 5, 6, 5], 5) // Return [1, 2, 3, 4, 6]

Також є сторонні бібліотеки, які допомагають вам це зробити, як-то Лодаш або Підкреслення. Для отримання додаткової інформації дивіться на lodash _.pull, _.pullAt або _.without.


Є невеликий друкарський помилок. Будь ласка, виправте. this.splice(num.indexOf(x), 1);=>this.splice(this.indexOf(x), 1);
TheGwa

Будь ласка, не збільшуйте вбудовані модулі (додайте функції до Array.prototype) у JavaScript. Це широко вважається поганою практикою.
айкеру

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

Ви повинні перевірити індекс. Якщо індекс = -1, сплайс (-1,1) видалить останній елемент
Річард Чан,

29

Я досить новачок у JavaScript і мені потрібна ця функціональність. Я просто написав це:

function removeFromArray(array, item, index) {
  while((index = array.indexOf(item)) > -1) {
    array.splice(index, 1);
  }
}

Тоді, коли я хочу його використовувати:

//Set-up some dummy data
var dummyObj = {name:"meow"};
var dummyArray = [dummyObj, "item1", "item1", "item2"];

//Remove the dummy data
removeFromArray(dummyArray, dummyObj);
removeFromArray(dummyArray, "item2");

Вихід - Як очікувалося. ["item1", "item1"]

У вас можуть бути інші потреби, ніж у мене, тому ви можете легко модифікувати це відповідно до них. Я сподіваюся, що це комусь допоможе.


1
Це матиме жахливу поведінку, якщо ваш масив дійсно довгий і в ньому є кілька примірників елемента. Метод масиву indexOf запускатиметься на початку кожного разу, тому ваша вартість буде O (n ^ 2).
Заг


27

Якщо у масиві є складні об'єкти, ви можете використовувати фільтри? У ситуаціях, коли $ .inArray або array.splice використовувати не так просто. Особливо, якщо об'єкти, можливо, дрібні в масиві.

Наприклад, якщо у вас є об'єкт із полем Id і ви хочете, щоб об’єкт був видалений з масиву:

this.array = this.array.filter(function(element, i) {
    return element.id !== idToRemove;
});

Ось як мені подобається це робити. За допомогою функції стрілки це може бути однолінійний. Мені цікаво виконання. Також нічого не варто, що це замінює масив. Будь-який код із посиланням на старий масив зміни не помітить.
joeytwiddle

27

Я хочу відповісти на основі ECMAScript 6 . Припустимо, у вас є масив, як показано нижче:

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

Якщо ви хочете видалити спеціальний індекс, як 2 , напишіть код нижче:

arr.splice(2, 1); //=> arr became [1,2,4]

Але якщо ви хочете видалити спеціальний елемент типу 3 і ви не знаєте його індексу, зробіть, як показано нижче:

arr = arr.filter(e => e !== 3); //=> arr became [1,2,4]

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


25

Оновлення: Цей метод рекомендується використовувати лише в тому випадку, якщо ви не можете використовувати ECMAScript 2015 (раніше відомий як ES6). Якщо ви можете скористатися нею, інші відповіді тут дають набагато акуратніші реалізації.


Цей суть тут вирішить вашу проблему, а також видалить усі випадки аргументу замість лише 1 (або заданого значення).

Array.prototype.destroy = function(obj){
    // Return null if no objects were found and removed
    var destroyed = null;

    for(var i = 0; i < this.length; i++){

        // Use while-loop to find adjacent equal objects
        while(this[i] === obj){

            // Remove this[i] and store it within destroyed
            destroyed = this.splice(i, 1)[0];
        }
    }

    return destroyed;
}

Використання:

var x = [1, 2, 3, 3, true, false, undefined, false];

x.destroy(3);         // => 3
x.destroy(false);     // => false
x;                    // => [1, 2, true, undefined]

x.destroy(true);      // => true
x.destroy(undefined); // => undefined
x;                    // => [1, 2]

x.destroy(3);         // => null
x;                    // => [1, 2]

25

Продуктивність

Сьогодні (2019-12-09) я провожу тести на продуктивність на macOS v10.13.6 (High Sierra) для обраних рішень. Я показую delete(A), але не використовую його порівняно з іншими методами, оскільки він залишив порожній простір у масиві.

Висновки

  • найшвидшим рішенням є array.splice(C) (за винятком Safari для малих масивів, де це є вдруге)
  • для великих масивів array.slice+splice(H) - це найшвидше незмінне рішення для Firefox та Safari; Array.from(B) найшвидший у Chrome
  • мутаційні розчини зазвичай на 1,5x-6x швидші, ніж незмінні
  • для невеликих таблиць на Safari напрочуд змінне рішення (C) повільніше, ніж незмінний розчин (G)

Деталі

У тестах я видаляю середній елемент з масиву різними способами. Рішення A, C є на місці. В, D, Е, F, G, H розчини є незмінними.

Результати для масиву з 10 елементами

Введіть тут опис зображення

У Chrome array.splice(C) - це найшвидше рішення на місці. array.filter(D) , є самим незаперечним рішенням. Найповільніший - array.slice(F). Ви можете виконати тест на своїй машині тут .

Результати для масиву з 1.000.000 елементів

Введіть тут опис зображення

У Chrome array.splice(C) - це найшвидший на місці рішення ( delete(C) схожий швидко - але він залишив порожній проріз у масиві (тому він не виконує "повне видалення")). array.slice-splice(Н) є самим незаперечним рішенням. Найповільніший - array.filter(D і E). Ви можете виконати тест на своїй машині тут .

Порівняння для браузерів: Chrome v78.0.0, Safari v13.0.4 та Firefox v71.0.0

Введіть тут опис зображення


24

Ви ніколи не повинні мутувати свій масив. Оскільки це суперечить схемі функціонального програмування. Ви можете створити новий масив, не посилаючись на масив, для якого потрібно змінити дані використання методу ECMAScript 6 filter;

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

Припустимо, ви хочете видалити 5з масиву, ви можете просто зробити це так:

myArray = myArray.filter(value => value !== 5);

Це дасть вам новий масив без значення, яке ви хотіли видалити. Тож результат буде:

 [1, 2, 3, 4, 6]; // 5 has been removed from this array

Для подальшого розуміння ви можете прочитати документацію MDN на Array.filter .


21

Більш сучасний підхід ECMAScript 2015 (раніше відомий як Harmony або ES 6). Подано:

const items = [1, 2, 3, 4];
const index = 2;

Тоді:

items.filter((x, i) => i !== index);

Вихід:

[1, 2, 4]

Ви можете використовувати Babel та послугу поліфункції, щоб переконатися, що це добре підтримується у веб-переглядачах.


4
Зауважте, що .filterповертається новий масив, який не є точно таким, як видалення елемента з того ж масиву. Перевага такого підходу полягає в тому, що ви можете поєднувати методи масиву разом. наприклад:[1,2,3].filter(n => n%2).map(n => n*n) === [ 1, 9 ]
CodeOcelot

Чудово, якщо я маю 600k елементів у масиві і хочу видалити перші 50k, чи можете ви уявити цю повільність? Це не рішення, необхідна функція, яка просто видаляє елементи і нічого не повертає.
dev1223

@Seraph Для цього ви, ймовірно, хочете використовувати spliceабо slice.
bjfletcher

@bjfletcher Ось ще краще, в процесі видалення просто виділіть 50K елементів і киньте їх кудись. (з фрагментами 550K елементів, але не викидаючи їх з вікна).
dev1223

Я вважаю за краще відповідь bjfletcher, яка може бути такою ж короткою items= items.filter(x=>x!=3). Крім того, ОП не виклала жодних вимог до великого набору даних.
runun

21

У вас в масиві від 1 до 9, і ви хочете видалити 5. Використовуйте наведений нижче код:

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];

var newNumberArray = numberArray.filter(m => {
  return m !== 5;
});

console.log("new Array, 5 removed", newNumberArray);


Якщо потрібно декілька значень. Приклад: - 1,7,8

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];

var newNumberArray = numberArray.filter(m => {
  return (m !== 1) && (m !== 7) && (m !== 8);
});

console.log("new Array, 1,7 and 8 removed", newNumberArray);


Якщо ви хочете видалити значення масиву з масиву. Приклад: [3,4,5]

var numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var removebleArray = [3,4,5];

var newNumberArray = numberArray.filter(m => {
    return !removebleArray.includes(m);
});

console.log("new Array, [3,4,5] removed", newNumberArray);

Включає підтримуваний браузер посилання .


19

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

Автономна функція

function removeAll(array, key){
    var index = array.indexOf(key);

    if(index === -1) return;

    array.splice(index, 1);
    removeAll(array,key);
}

Метод прототипу

Array.prototype.removeAll = function(key){
    var index = this.indexOf(key);

    if(index === -1) return;

    this.splice(index, 1);
    this.removeAll(key);
}

Лише зауважте, 1 застереження за допомогою цього методу - це потенціал для переповнення стека. Якщо ви не працюєте з масивними масивами, у вас не повинно виникнути проблем.
wharding28

Але чому повернення в середині? Це фактично goto заява.
Пітер Мортенсен

18

Ви можете зробити зворотний цикл, щоб переконатися, що не вкручувати індекси, якщо є кілька примірників елемента.

var myElement = "chocolate";
var myArray = ['chocolate', 'poptart', 'poptart', 'poptart', 'chocolate', 'poptart', 'poptart', 'chocolate'];

/* Important code */
for (var i = myArray.length - 1; i >= 0; i--) {
    if (myArray[i] == myElement) myArray.splice(i, 1);
}

Демонстраційна демонстрація

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