Как отфильтровать массив из всех элементов другого массива





Я хотел бы понять, как лучше всего фильтровать массив из всех элементов другого. Я пробовал с функцией фильтра, но он не приходит ко мне, как дать ему значения, которые я хочу удалить.
Что-То Типа:



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 легко. Ответ проверил, как хорошо делает вещи легко.

1755   14  

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 - в anotherOne

https://jsfiddle.net/0tsyc1sx/

если вы используете lodash.js используйте _.difference

filteredArray = _.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
});

демонстрационный массив объектов

Demo diff массив объектов с lodash

        /* 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

    Ничего не найдено.