Как удалить определенный элемент из массива в JavaScript?



Answers

Я не знаю, как вы ожидаете, что 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];
Question

У меня есть массив целых чисел, и я использую метод .push() для добавления к нему элементов.

Есть ли простой способ удалить определенный элемент из массива? Эквивалент чего-то типа array.remove(int); ,

Я должен использовать базовый JavaScript - никакие рамки не разрешены.




2017-05-08

Most of the given answers work for strict comparison, meaning that both objects reference the exact same object in memory (or are primitive types), but often you want to remove a non-primitive object from an array that has a certain value. For instance, if you make a call to a server and want to check a retrieved object against a local object.

const a = {'field': 2} // Non-primitive object
const b = {'field': 2} // Non-primitive object with same value
const c = a            // Non-primitive object that reference the same object as "a"

assert(a !== b) // Don't reference the same item, but have same value
assert(a === c) // Do reference the same item, and have same value (naturally)

//Note: there are many alternative implementations for valuesAreEqual
function valuesAreEqual (x, y) {
   return  JSON.stringify(x) === JSON.stringify(y)
}


//filter will delete false values
//Thus, we want to return "false" if the item
// we want to delete is equal to the item in the array
function removeFromArray(arr, toDelete){
    return arr.filter(target => {return !valuesAreEqual(toDelete, target)})
}

const exampleArray = [a, b, b, c, a, {'field': 2}, {'field': 90}];
const resultArray = removeFromArray(exampleArray, a);

//resultArray = [{'field':90}]

There are alternative/faster implementations for valuesAreEqual, but this does the job. You can also use a custom comparator if you have a specific field to check (for example, some retrieved UUID vs a local UUID).

Also note that this is a functional operation, meaning that it does not mutate the original array.




Зависит от того, хотите ли вы сохранить пустое место или нет.

Если вам нужен пустой слот, удаление будет прекрасным:

delete array[ index ];

Если вы этого не сделаете, вы должны использовать метод splice :

array.splice( index, 1 );

И если вам нужно значение этого элемента, вы можете просто сохранить элемент возвращенного массива:

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

Если вы хотите сделать это в некотором порядке, вы можете использовать array.pop() для последнего или array.shift() для первого (и оба возвращают значение элемента тоже).

И если вы не знаете индекс элемента, вы можете использовать array.indexOf( item ) чтобы получить его (в if() чтобы получить один элемент или через некоторое while() чтобы получить все из них). array.indexOf( item ) возвращает либо индекс, либо -1, если не найден.




Если у вас есть сложные объекты в массиве, вы можете использовать фильтры? В ситуациях, когда $ .inArray или array.splice не так просты в использовании. Особенно, если объекты, возможно, мелкие в массиве.

Например, если у вас есть объект с полем Id и вы хотите, чтобы объект был удален из массива:

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



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

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]




Я довольно новичок в 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"]

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




Вы можете использовать lodash _.pull (mutate array), _.pullAt (mutate array) или _.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']



Более современный подход ECMAScript 2015 (ранее известный как Harmony или ES 6). Данный:

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

Затем:

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

Уступая:

[1, 2, 4]

Вы можете использовать Babel и службу polyfill, чтобы гарантировать, что это хорошо поддерживается в браузерах.




Создать новый массив:

var my_array = new Array();

Добавьте элементы в этот массив:

my_array.push("element1");

Функция indexOf (возвращает индекс или -1, если не найден):

var indexOf = function(needle) 
{
    if(typeof Array.prototype.indexOf === 'function') // newer browsers
    {
        indexOf = Array.prototype.indexOf;
    } 
    else // older browsers
    {
        indexOf = function(needle) 
        {
            var index = -1;

            for(var i = 0; i < this.length; i++) 
            {
                if(this[i] === needle) 
                {
                    index = i;
                    break;
                }
            }
            return index;
        };
    }

    return indexOf.call(this, needle);
};

Проверьте индекс этого элемента (проверено с помощью firefox и IE8 +):

var index = indexOf.call(my_array, "element1");

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

my_array.splice(index, 1);



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

// 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-элементный массив. Не знаю, почему, но я подтвердил, что первоначальная реализация Джона не имеет этой проблемы.




Удалить по индексу

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

/**
* removeByIndex
* @param {Array} array
* @param {Number} index
*/
function removeByIndex(array, index){
    return array.filter(function(elem, _index){
        return index != _index;
    });
}
l = [1,3,4,5,6,7];
console.log(removeByIndex(l, 1));

$> [ 1, 4, 5, 6, 7 ]

Удалить по стоимости

Функция, возвращающая копию массива без значения.

/**
* removeByValue
* @param {Array} array
* @param {Number} value
*/
function removeByValue(array, value){
    return array.filter(function(elem, _index){
        return value != elem;
    });
}
l = [1,3,4,5,6,7];
console.log(removeByValue(l, 5));

$> [ 1, 3, 4, 6, 7]



Существует два основных подхода:

  1. splice () : anArray.splice(index, 1);

  2. delete : delete anArray[index];

Будьте осторожны, когда вы используете delete для массива. Он хорош для удаления атрибутов объектов, но не так хорош для массивов. Лучше использовать splice для массивов.

Имейте в виду, что когда вы используете delete для массива, вы можете получить неправильные результаты для anArray.length . Другими словами, delete удаляет элемент, но не обновляет значение свойства length.

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

Если вы по какой-то причине вынуждены использовать delete , тогда вам нужно использовать for each петли, когда вам нужно перебирать массивы. По сути дела, всегда избегайте использования индексированных для петель, если это возможно. Таким образом, код будет более надежным и менее подверженным проблемам с индексами.




Я знаю, что уже есть много ответов, но многие из них, похоже, усложняют проблему. Вот простой, рекурсивный способ удаления всех экземпляров ключа - вызывает self, пока индекс не будет найден. Да, он работает только в браузерах с 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);
}



Нет необходимости использовать 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



Вы можете сделать это легко с помощью метода filter :

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

Это удаляет все элементы из массива, а также работает быстрее, чем комбинация среза и indexOf




Links