Удаление нескольких элементов из массива в Javascript/jQuery
у меня есть два массива. Первый массив содержит некоторые значения, а второй массив содержит индексы значений, которые должны быть удалены из первого массива. Например:
var valuesArr = new Array("v1","v2","v3","v4","v5");
var removeValFromIndex = new Array(0,2,4);
Я хочу удалить значения, присутствующие в индексах 0,2,4 С valuesArr. Я думал, что родной splice метод может помочь, поэтому я придумал:
$.each(removeValFromIndex,function(index,value){
valuesArr.splice(value,1);
});
но это не сработало, потому что после каждого splice индексы значений valuesArr были разные. Я мог бы решить эту проблему проблема с использованием временного массива и копированием всех значений во второй массив, но мне было интересно, есть ли какие-либо собственные методы, которым мы можем передать несколько индексов, на которых можно удалить значения из массива.
Я бы предпочел решение на jQuery. (Не уверен, что я могу использовать grep здесь)
19 ответов:
всегда есть старый добрый
forпетли:var valuesArr = ["v1","v2","v3","v4","v5"], removeValFromIndex = [0,2,4]; for (var i = removeValFromIndex.length -1; i >= 0; i--) valuesArr.splice(removeValFromIndex[i],1);пройти
removeValFromIndexв обратном порядке и вы можете.splice()не испортив индексы еще не удаленных элементов.Примечание В приведенном выше я использовал массив-литеральный синтаксис с квадратными скобками для объявления двух массивов. Это рекомендуемый синтаксис, потому что
new Array()использовать потенциально запутанным, учитывая, что он реагирует по-разному в зависимости от того, сколько параметров вы передаете в.EDIT: только что видел ваш комментарий к другому ответу о массиве индексов, не обязательно находящихся в каком-либо определенном порядке. Если это так, просто отсортируйте его в порядке убывания, прежде чем начать:
removeValFromIndex.sort(function(a,b){ return b - a; });и следуйте за этим с любым циклом/
$.each()/ etc. метод вам нравится.
не
in-placeно можно сделать с помощьюgrepиinArrayфункцииjQuery.var arr = $.grep(valuesArr, function(n, i) { return $.inArray(i, removeValFromIndex) ==-1; }); alert(arr);//arr contains V2, V4Регистрация этой скрипка.
вот тот, который я использую, когда не иду с lodash / underscore:
while(IndexesToBeRemoved.length) { elements.splice(IndexesToBeRemoved.pop(), 1); }
function filtermethod(element, index, array) { return removeValFromIndex.find(index) } var result = valuesArr.filter(filtermethod);ссылка MDN-это здесь
Я предлагаю вам использовать массив.прототип.фильтр
var valuesArr = ["v1","v2","v3","v4","v5"]; var removeValFrom = [0, 2, 4]; valuesArr = valuesArr.filter(function(value, index) { return removeValFrom.indexOf(index) == -1; })
в чистом JS вы можете перебирать массив назад, так что
splice()не испортит индексы элементов, следующих в цикле:for (var i = arr.length - 1; i >= 0; i--) { if ( yuck(arr[i]) ) { arr.splice(i, 1); } }
он чувствует, что необходимо опубликовать ответ с
O(n)времени :). Проблема с решением splice заключается в том, что из-за базовой реализации array being буквально массив, каждыйspliceзвонок будет приниматьO(n)времени. Это наиболее заметно, когда мы устанавливаем пример для использования этого поведения:var n = 100 var xs = [] for(var i=0; i<n;i++) xs.push(i) var is = [] for(var i=n/2-1; i>=0;i--) is.push(i)это удаляет элементы, начиная с середины до начала, поэтому каждое удаление заставляет двигатель js копировать
n/2элементы, у нас есть(n/2)^2операции копирования в общей сложности, которая является квадратичной.решение для сращивания (предполагая
isуже отсортирован в порядке убывания, чтобы избавиться от накладных расходов) идет так:for(var i=0; i<is.length; i++) xs.splice(is[i], 1)тем не менее, нетрудно реализовать линейное временное решение, перестроив массив с нуля, используя маску, чтобы увидеть, копируем ли мы элементы или нет (сортировка будет толкать это к
O(n)log(n)). Ниже приводится такая реализация (не то, чтоmask- это логическое перевернутый для скорость):var mask = new Array(xs.length) for(var i=is.length - 1; i>=0; i--) mask[is[i]] = true var offset = 0 for(var i=0; i<xs.length; i++){ if(mask[i] === undefined){ xs[offset] = xs[i] offset++ } } xs.length = offsetя запустил это на jsperf.com и даже
n=100метод соединения является полным 90% медленнее. Для большихnэта разница будет значительно больше.
простое решение с использованием ES5. Это кажется более подходящим для большинства приложений в настоящее время, так как многие больше не хотят полагаться на jQuery и т. д.
когда удаляемые индексы сортируются в порядке возрастания:
var valuesArr = ["v1", "v2", "v3", "v4", "v5"]; var removeValFromIndex = [0, 2, 4]; // ascending removeValFromIndex.reverse().forEach(function(index) { valuesArr.splice(index, 1); });когда удаляемые индексы не сортируются:
var valuesArr = ["v1", "v2", "v3", "v4", "v5"]; var removeValFromIndex = [2, 4, 0]; // unsorted removeValFromIndex.sort(function(a, b) { return b - a; }).forEach(function(index) { valuesArr.splice(index, 1); });
вы можете исправить ваш код, заменив
removeValFromIndexсremoveValFromIndex.reverse(). Если этот массив не гарантированно использовать в порядке возрастания, вы можете вместо этого использоватьremoveValFromIndex.sort(function(a, b) { return b - a }).
вот один вариант:
valuesArr = removeValFromIndex.reduceRight(function (arr, it) { arr.splice(it, 1); return arr; }, valuesArr.sort(function (a, b) { return b - a }));
если вы используете подчеркивания.js, вы можете использовать
_.filter(), чтобы решить вашу проблему.var valuesArr = new Array("v1","v2","v3","v4","v5"); var removeValFromIndex = new Array(0,2,4); var filteredArr = _.filter(valuesArr, function(item, index){ return !_.contains(removeValFromIndex, index); });кроме того, если вы пытаетесь удалить элементы, используя список элементов вместо индексов, вы можете просто использовать
_.without(), например:var valuesArr = new Array("v1","v2","v3","v4","v5"); var filteredArr = _.without(valuesArr, "V1", "V3");теперь
filteredArrдолжно быть["V2", "V4", "V5"]
вот по-быстрому.
function removeFromArray(arr, toRemove){ return arr.filter(item => toRemove.indexOf(item) === -1) } const arr1 = [1, 2, 3, 4, 5, 6, 7] const arr2 = removeFromArray(arr1, [2, 4, 6]) // [1,3,5,7]
вот немного более оптимизированная версия принятых ответов. во-первых, мы можем настроить вызов соединения так, что мы удаляем несколько последовательных элементов в одном вызове. другая оптимизация заключается в том, чтобы прервать цикл раньше, если мы удалили все элементы из массива (в typescript):
function removeFromArray(arr: any[], elements: any[]) { let deleteCount = 0, total = elements.length for (let i = arr.length; i--;) { if (~elements.indexOf(arr[i])) { deleteCount++ // optimize removal of consecutive elements } else if (deleteCount) { arr.splice(i + 1, deleteCount) if ((total -= deleteCount) === 0) { // if we removed all already, break early deleteCount = 0 break } deleteCount = 0 } } if (deleteCount) { arr.splice(0, deleteCount) } }
для нескольких элементов или уникальный элемент:
Я предлагаю вам использовать массив.прототип.фильтр
никогда не используйте indexOf если вы уже знаете индекс!:
var valuesArr = ["v1","v2","v3","v4","v5"]; var removeValFrom = [0, 2, 4]; valuesArr = valuesArr.filter(function(value, index) { return removeValFrom.indexOf(index) == -1; }); // BIG O(N*m) where N is length of valuesArr and m is length removeValFromDo:
с хэшами... используя массив.прототип.карта
var valuesArr = ["v1","v2","v3","v4","v5"]; var removeValFrom = {}; ([0, 2, 4]).map(x=>removeValFrom[x]=1); //bild the hash. valuesArr = valuesArr.filter(function(value, index) { return removeValFrom[index] == 1; }); // BIG O(N) where N is valuesArr;
быстрый ES6 один лайнер:
const valuesArr = new Array("v1","v2","v3","v4","v5"); const removeValFromIndex = new Array(0,2,4); const arrayWithValuesRemoved = valuesArr.filter((value, i) => removeValFromIndex.includes(i))
var valuesArr = new Array("v1","v2","v3","v4","v5"); var removeValFromIndex = new Array(0,2,4); console.log(valuesArr) let arr2 = []; for (let i = 0; i < valuesArr.length; i++){ if ( //could also just imput this below instead of index value valuesArr[i] !== valuesArr[0] && // "v1" <-- valuesArr[i] !== valuesArr[2] && // "v3" <-- valuesArr[i] !== valuesArr[4] // "v5" <-- ){ arr2.push(valuesArr[i]); } } console.log(arr2);это работает. Однако в этом процессе вы создадите новый массив. Не уверен, хотите ли вы этого или нет, но технически это будет массив, содержащий только те значения, которые вы хотели.
вы можете попробовать и использовать
delete array[index]Это не будет полностью удалить элемент, а, скорее, устанавливает значениеundefined.
звучит как применить может быть то, что вы ищете.
может быть, что-то вроде этого сработает?Array.prototype.splice.apply(valuesArray, removeValFromIndexes );
Comments