Как отфильтровать массив из всех элементов другого массива
Я хотел бы понять, как лучше всего фильтровать массив из всех элементов другого. Я пробовал с функцией фильтра, но он не приходит ко мне, как дать ему значения, которые я хочу удалить.
Что-То Типа:
var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallback);
// filteredArray should now be [1,3]
function myCallBack(){
return element ! filteredArray;
//which clearly can't work since we don't have the reference <,<
}
если функция фильтра не полезна, как бы вы это реализовали ?
Edit: я проверил возможный дубликат вопроса, и это может быть полезно для тех, кто понимает javascript легко. Ответ проверил, как хорошо делает вещи легко.
14 ответов:
можно использовать
thisпараметр функции filter (), чтобы избежать сохранения массива фильтров в глобальной переменной.var filtered = [1, 2, 3, 4].filter( function(e) { return this.indexOf(e) < 0; }, [2, 4] );
Я бы сделал следующим образом:
var arr = [1,2,3,4], brr = [2,4], res = arr.filter(f => !brr.includes(f)); console.log(res);
var array = [1,2,3,4]; var anotherOne = [2,4]; var filteredArray = array.filter(myCallBack); function myCallBack(el){ return anotherOne.indexOf(el) < 0; }в обратном вызове, вы проверяете, если каждое значение
array- вanotherOnehttps://jsfiddle.net/0tsyc1sx/
если вы используете
lodash.jsиспользуйте_.differencefilteredArray = _.difference(array, anotherOne);если у вас есть массив объектов :
var array = [{id :1, name :"test1"},{id :2, name :"test2"},{id :3, name :"test3"},{id :4, name :"test4"}]; var anotherOne = [{id :2, name :"test2"}, {id :4, name :"test4"}]; var filteredArray = array.filter(function(array_el){ return anotherOne.filter(function(anotherOne_el){ return anotherOne_el.id == array_el.id; }).length == 0 });
/* Here's an example that uses (some) ES6 Javascript semantics to filter an object array by another object array. */ // x = full dataset // y = filter dataset let x = [ {"val": 1, "text": "a"}, {"val": 2, "text": "b"}, {"val": 3, "text": "c"}, {"val": 4, "text": "d"}, {"val": 5, "text": "e"} ], y = [ {"val": 1, "text": "a"}, {"val": 4, "text": "d"} ]; // Use map to get a simple array of "val" values. Ex: [1,4] let yFilter = y.map(itemY => { return itemY.val; }); // Use filter and "not" includes to filter the full dataset by the filter dataset's val. let filteredX = x.filter(itemX => !yFilter.includes(itemX.val)); // Print the result. console.log(filteredX);
лучшее описание к
filterфункция есть https://developer.mozilla.org/pl/docs/Web/JavaScript/Referencje/Obiekty/Array/filterвы должны просто условие функции:
function conditionFun(element, index, array) { return element >= 10; } filtered = [12, 5, 8, 130, 44].filter(conditionFun);и вы не можете получить доступ к значению переменной, прежде чем она будет назначена
вы можете использовать фильтр, а затем для функции фильтра использовать сокращение массива фильтрации, который проверяет и возвращает true, когда он находит совпадение, а затем инвертирует при возврате (!). Функция-фильтр вызывается один раз для каждого элемента в массиве. Вы не делаете сравнение каких-либо элементов в функции в вашем посте.
var a1 = [1, 2, 3, 4], a2 = [2, 3]; var filtered = a1.filter(function(x) { return !a2.reduce(function(y, z) { return x == y || x == z || y == true; }) }); document.write(filtered);
более гибкий массив фильтрации из другого массива, который содержит свойства объекта
function filterFn(array, diffArray, prop, propDiff) { diffArray = !propDiff ? diffArray : diffArray.map(d => d[propDiff]) this.fn = f => diffArray.indexOf(f) === -1 if (prop) { return array.map(r => r[prop]).filter(this.fn) } else { return array.filter(this.fn) } } //You can use it like this; var arr = []; for (var i = 0; i < 10; i++) { var obj = {} obj.index = i obj.value = Math.pow(2, i) arr.push(obj) } var arr2 = [1, 2, 3, 4, 5] var sec = [{t:2}, {t:99}, {t:256}, {t:4096}] var log = console.log.bind(console) var filtered = filterFn(arr, sec, 'value', 't') var filtered2 = filterFn(arr2, sec, null, 't') log(filtered, filtered2)
В следующих примерах используется
new Set()чтобы создать отфильтрованный массив, содержащий только уникальные элементы:массив с примитивными типами данных: string, number, boolean, null, undefined, symbol:
const a = [1, 2, 3, 4]; const b = [3, 4, 5]; const c = Array.from(new Set(a.concat(b)));массив с объектами в виде элементов:
const a = [{id:1}, {id: 2}, {id: 3}, {id: 4}]; const b = [{id: 3}, {id: 4}, {id: 5}]; const stringifyObject = o => JSON.stringify(o); const parseString = s => JSON.parse(s); const c = Array.from(new Set(a.concat(b).map(stringifyObject)), parseString);
все вышеперечисленные решения "работают", но менее оптимальны для производительности и все они подходят к проблеме таким же образом, который линейно ищет все записи в каждой точке с помощью массив.прототип.indexOf или массив.прототип.включает в себя. Гораздо более быстрым решением (гораздо быстрее, чем двоичный поиск в большинстве случаев) было бы сортировать массивы и пропускать вперед, как показано ниже. Однако одним из недостатков является то, что для этого требуются все записи в массиве быть числами или строками. Кроме того, двоичный поиск может в некоторых редких случаях быть быстрее, чем прогрессивный линейный поиск. Эти случаи возникают из-за того, что мой прогрессивный линейный поиск имеет сложность O (2n1+n2) (всего O (n1+n2) в более быстрой версии C / C++) (где n1 это искомый массив и n2 - это массив фильтров), тогда как двоичный поиск имеет сложность O (n1ceil (log2n2)) (ceil = round up - to the ceiling), и, наконец, поиск indexOf имеет очень переменную сложность между O (n1) и O (n1n2) в среднем на O (n1ceil (n2÷2)). Таким образом, indexOf будет только самым быстрым, в среднем, в случаях из (n1, n2) в размере {1,2}, {1,3} или {x, 1|x∈N}. Однако это все еще не идеальное представление современного оборудования. IndexOf изначально оптимизирован в максимально возможной степени в большинстве современных браузеров, что делает его очень подверженным законам предсказания ветвлений. Таким образом, если мы сделаем то же предположение об indexOf, что и при прогрессивном линейном и двоичном поиске, то массив предварительно сортируется -- тогда, согласно статистике, приведенной в ссылке, мы можем ожидать примерно 6-кратного ускорения для IndexOf, смещая его сложность между O (n1÷6) и O (n1n2) в среднем на O (n1ceil (n27÷12)). Наконец, обратите внимание, что ниже решение никогда не будет работать с объектами, потому что невозможно получить внутренний указатель объекта (для численного сравнения) в Яваскрипт.
function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); } function sortIntArray(a,b) { return a - b; } var Math_clz32 = Math.clz32; function filterArrayByAnotherArray(searchArray, filterArray, isInteger = false, i = 0) { if (isInteger) { // if all entries in both arrays are integers searchArray.sort(sortIntArray); filterArray.sort(sortIntArray); } else { searchArray.sort(sortAnyArray); filterArray.sort(sortAnyArray); } var searchArrayLen = searchArray.length, filterArrayLen = filterArray.length; var progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0 var binarySearchComplexity= (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0; // After computing the complexity, we can predict which algorithm will be the fastest if (progressiveLinearComplexity < binarySearchComplexity) { // Progressive Linear Search return searchArray.filter(function(currentValue){ while (filterArray[i] < currentValue) ++i; // +undefined = NaN, which is always false for <, avoiding an infinite loop return filterArray[i] !== currentValue; }); } else { // Binary Search return searchArray.filter(function(currentValue) { var lo = -1, hi = filterArrayLen; while (1 + lo !== hi) { const mi = (hi + lo) >> 1; if (currentValue <= filterArray[mi]) hi = mi; else lo = mi; } return filterArray[hi] !== currentValue; }); } }для того чтобы оценить разницу в скорости, давайте рассмотрим некоторые JSPerfs. Ибо фильтрация массива из 16 элементов, двоичный поиск примерно на 17% быстрее, чем indexOf в то время как filterArrayByAnotherArray примерно на 93% быстрее, чем indexOf. Ибо фильтрация массива из 256 элементов, двоичный поиск примерно на 291% быстрее, чем indexOf в то время как filterArrayByAnotherArray примерно на 353% быстрее, чем indexOf. Ибо фильтрация массива 4096 элементы, двоичный поиск примерно на 2655% быстрее, чем indexOf в то время как filterArrayByAnotherArray примерно на 4627% быстрее, чем indexOf.
OA также может быть реализован в ES6 следующим образом
ES6:
const filtered = [1, 2, 3, 4].filter(e => { return this.indexOf(e) < 0; },[2, 4]);
вы можете настроить функцию фильтра для итерации по "массиву фильтров".
var arr = [1, 2, 3 ,4 ,5, 6, 7]; var filter = [4, 5, 6]; var filtered = arr.filter( function(val) { for (var i = 0; i < filter.length; i++) { if (val == filter[i]) { return false; } } return true; } );
var arr1= [1,2,3,4]; var arr2=[2,4] function fil(value){ return value !=arr2[0] && value != arr2[1] } document.getElementById("p").innerHTML= arr1.filter(fil)<!DOCTYPE html> <html> <head> </head> <body> <p id="p"></p>
function arr(arr1,arr2){ function filt(value){ return arr2.indexOf(value) === -1; } return arr1.filter(filt) } document.getElementById("p").innerHTML = arr([1,2,3,4],[2,4])<p id="p"></p>
вы можете написать общую функцию filterByIndex () и использовать вывод типа в TS, чтобы сэкономить хлопоты с функцией обратного вызова:
допустим, у вас есть массив [1,2,3,4], который вы хотите отфильтровать() с индексами, указанными в массиве [2,4].
var filtered = [1,2,3,4,].filter(byIndex(element => element, [2,4]))функция byIndex ожидает функцию элемента и массив и выглядит следующим образом:
byIndex = (getter: (e:number) => number, arr: number[]) => (x: number) => { var i = getter(x); return arr.indexOf(i); }результат
filtered = [1,3]
Comments