Javascript 如何从另一个数组的所有元素中过滤一个数组

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34901593/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:01:13  来源:igfitidea点击:

How to filter an array from all elements of another array

javascriptarraysfilter

提问by Koop4


I'd like to understand the best way to filter an array from all elements of another one. I tried with the filter function, but it doesn't come to me how to give it the values i want to remove.
Something Like:


我想了解从另一个数组的所有元素中过滤数组的最佳方法。我尝试使用过滤器功能,但我不知道如何给它我想要删除的值。
就像是:

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 <,< 
}

in case the filter function is not usefull, how would you implement this ?
Edit: i checked the possible duplicate question, and it could be useful for those who understand javascript easily. The answer checked as good makes things easy.

如果过滤器功能没有用,您将如何实现?
编辑:我检查了可能重复的问题,它对那些容易理解 javascript 的人很有用。检查为好的答案使事情变得容易。

回答by Simon Hi

You can use the thisparameter of the filter()function to avoid to store your filter array in a global variable.

您可以使用函数的this参数filter()来避免将过滤器数组存储在全局变量中。

var filtered = [1, 2, 3, 4].filter(
    function(e) {
      return this.indexOf(e) < 0;
    },
    [2, 4]
);
console.log(filtered);

回答by Redu

I would do as follows;

我会这样做;

var arr = [1,2,3,4],
    brr = [2,4],
    res = arr.filter(f => !brr.includes(f));
console.log(res);

回答by AshBringer

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(myCallBack);

function myCallBack(el){
  return anotherOne.indexOf(el) < 0;
}

In the callback, you check if each value of arrayis in anotherOne

在回调中,您检查每个值array是否在anotherOne

https://jsfiddle.net/0tsyc1sx/

https://jsfiddle.net/0tsyc1sx/

If you are using lodash.js, use _.difference

如果您正在使用lodash.js,请使用_.difference

filteredArray = _.difference(array, anotherOne);

Demo

演示

If you have an array of objects :

如果您有一组对象:

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 array of objects

演示对象数组

Demo diff array of objects with lodash

使用 lodash 演示 diff 对象数组

回答by David Alan Condit

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

回答by Awais Jameel

This will be the Simplest way to filter an array with respect to another array. Both arrays can have objects inside them instead of values.

这将是相对于另一个数组过滤数组的最简单方法。两个数组都可以在其中包含对象而不是值。

let array1 = [1,3,47,1,6,7];
let array2 = [3,6];
let filteredArray1 = array1.filter(el => array2.includes(el));

filteredArray1 == [3,6] \\ these are the values of array1 after filter

filteredArray1 == [3,6] \\ 这些是过滤后 array1 的值

回答by Mati Cassanelli

There are many answers for your question, but I don't see anyone using lambda expresion:

您的问题有很多答案,但我没有看到有人使用 lambda 表达式:

var array = [1,2,3,4];
var anotherOne = [2,4];
var filteredArray = array.filter(x => anotherOne.indexOf(x) < 0);

回答by Hyman Giffin

All the above solutions "work", but are less than optimal for performance and are all approach the problem in the same way which is linearly searching all entries at each point using Array.prototype.indexOfor Array.prototype.includes. A far faster solution (far faster even than a binary search for most cases) would be to sort the arrays and skip ahead as you go along as seen below. However, one downside is that this requires all entries in the array to be numbers or strings. Also however, binary search may in some rare cases be faster than the progressive linear search. These cases arise from the fact that my progressive linear search has a complexity of O(2n1+n2)(only O(n1+n2)in the faster C/C++ version) (where n1is the searched array and n2is the filter array), whereas the binary search has a complexity of O(n1ceil(log2n2))(ceil = round up -- to the ceiling), and, lastly, the indexOf search has a highly variable complexity between O(n1)and O(n1n2), averaging out to O(n1ceil(n2÷2)). Thus, indexOf will only be the fastest, on average, in the cases of (n1,n2)equaling {1,2}, {1,3}, or {x,1|x∈N}. However, this is still not a perfect representation of modern hardware. IndexOf is natively optimized to the fullest extent imaginable in most modern browsers, making it very subject to the laws of branch prediction. Thus, if we make the same assumption on indexOf as we do with progressive linear and binary search -- that the array is presorted -- then, according to the stats listed in the link, we can expect roughly a 6x speed up for IndexOf, shifting its complexity to between O(n1÷6)and O(n1n2), averaging out to O(n1ceil(n27÷12)). Finally, take note that the below solution will never work with objects because it is impossible to get the internal object pointer (for numerical comparison) in javascript. If only Javascript could be

上述所有解决方案都“有效”,但都不是最佳性能,并且都以相同的方式解决问题,即使用Array.prototype.indexOfArray.prototype.includes在每个点线性搜索所有条目。一个更快的解决方案(在大多数情况下甚至比二分搜索快得多)是对数组进行排序并向前跳过,如下所示。但是,一个缺点是这要求数组中的所有条目都是数字或字符串。然而,在极少数情况下,二分搜索可能比渐进线性搜索更快。这些情况源于这样一个事实,即我的渐进线性搜索的复杂度为O(2n 1+n 2)(仅O(n 1+n 2)在更快的 C/C++ 版本中)(其中n 1是搜索的数组,n 2是过滤器数组),而二分搜索的复杂度为O(n 1ceil(log 2n 2))( ceil = 向上舍入 - 到上限),最后,indexOf 搜索在O(n 1)O(n 1n 2)之间具有高度可变的复杂性,平均为O(n 1ceil(n 2÷2))。因此,平均而言,indexOf 只会是最快的(n 1,n 2)等于{1,2}{1,3}{x,1|x∈N}。然而,这仍然不是现代硬件的完美代表。IndexOf 已在大多数现代浏览器中进行了最大程度的本地优化,使其非常受分支预测定律的约束。因此,如果我们对 indexOf 做出与渐进线性和二分搜索相同的假设——数组是预先排序的——那么,根据链接中列出的统计数据,我们可以预期 IndexOf 的速度大约提高 6 倍,将其复杂度转换为O(n 1÷6)O(n 1n 2),平均为O(n 1ceil(n 27÷12))。最后,请注意以下解决方案永远不会对对象起作用,因为在 javascript 中无法获取内部对象指针(用于数值比较)。如果只有 Javascript 可以

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }

const Math_clz32 = Math.clz32 || (function(log, LN2){
  return function(x) {
    return 31 - log(x >>> 0) / LN2 | 0; // the "| 0" acts like math.floor
  };
})(Math.log, Math.LN2);

function filterArrayByAnotherArray(searchArray, filterArray) {
    if (
        // NOTE: This does not check the whole array. But, if you know
        //        that there are only strings or numbers (not a mix of
        //        both) in the array, then this is a safe assumption.
        // Always use `==` with `typeof` because browsers can optimize
        //  the `==` into `===` (ONLY IN THIS CIRCUMSTANCE)
        typeof searchArray[0] == "number" &&
        typeof filterArray[0] == "number" &&
        (searchArray[0]|0) === searchArray[0] &&
        (filterArray[0]|0) === filterArray[0]
    ) {filterArray
        // 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
    var i = 0;
    if (progressiveLinearComplexity < binarySearchComplexity) {
        // Progressive Linear Search
        return searchArray.filter(function(currentValue){
            while (filterArray[i] < currentValue) i=i+1|0;
            // +undefined = NaN, which is always false for <, avoiding an infinite loop
            return filterArray[i] !== currentValue;
        });
    } else {
        // Binary Search
        return searchArray.filter(
            fastestBinarySearch(filterArray)
        );
    }
}

// see https://stackoverflow.com/a/44981570/5601591 for implementation
//  details about this binary search algorithim

function fastestBinarySearch(array){
  var initLen = (array.length|0) - 1 |0;

  const compGoto = Math_clz32(initLen) & 31;
  return function(ARG_sValue) {
    var sValue = ARG_sValue |0;
    var len = initLen |0;
    switch (compGoto) {
      case 0:
        if (len & 0x80000000) {
          const nCB = len & 0x80000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 1:
        if (len & 0x40000000) {
          const nCB = len & 0xc0000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 2:
        if (len & 0x20000000) {
          const nCB = len & 0xe0000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 3:
        if (len & 0x10000000) {
          const nCB = len & 0xf0000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 4:
        if (len & 0x8000000) {
          const nCB = len & 0xf8000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 5:
        if (len & 0x4000000) {
          const nCB = len & 0xfc000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 6:
        if (len & 0x2000000) {
          const nCB = len & 0xfe000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 7:
        if (len & 0x1000000) {
          const nCB = len & 0xff000000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 8:
        if (len & 0x800000) {
          const nCB = len & 0xff800000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 9:
        if (len & 0x400000) {
          const nCB = len & 0xffc00000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 10:
        if (len & 0x200000) {
          const nCB = len & 0xffe00000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 11:
        if (len & 0x100000) {
          const nCB = len & 0xfff00000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 12:
        if (len & 0x80000) {
          const nCB = len & 0xfff80000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 13:
        if (len & 0x40000) {
          const nCB = len & 0xfffc0000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 14:
        if (len & 0x20000) {
          const nCB = len & 0xfffe0000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 15:
        if (len & 0x10000) {
          const nCB = len & 0xffff0000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 16:
        if (len & 0x8000) {
          const nCB = len & 0xffff8000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 17:
        if (len & 0x4000) {
          const nCB = len & 0xffffc000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 18:
        if (len & 0x2000) {
          const nCB = len & 0xffffe000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 19:
        if (len & 0x1000) {
          const nCB = len & 0xfffff000;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 20:
        if (len & 0x800) {
          const nCB = len & 0xfffff800;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 21:
        if (len & 0x400) {
          const nCB = len & 0xfffffc00;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 22:
        if (len & 0x200) {
          const nCB = len & 0xfffffe00;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 23:
        if (len & 0x100) {
          const nCB = len & 0xffffff00;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 24:
        if (len & 0x80) {
          const nCB = len & 0xffffff80;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 25:
        if (len & 0x40) {
          const nCB = len & 0xffffffc0;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 26:
        if (len & 0x20) {
          const nCB = len & 0xffffffe0;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 27:
        if (len & 0x10) {
          const nCB = len & 0xfffffff0;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 28:
        if (len & 0x8) {
          const nCB = len & 0xfffffff8;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 29:
        if (len & 0x4) {
          const nCB = len & 0xfffffffc;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 30:
        if (len & 0x2) {
          const nCB = len & 0xfffffffe;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
      case 31:
        if (len & 0x1) {
          const nCB = len & 0xffffffff;
          len ^= (len ^ (nCB-1)) & ((array[nCB] <= sValue |0) - 1 >>>0);
        }
    }
    // MODIFICATION: Instead of returning the index, this binary search
    //                instead returns whether something was found or not.
    if (array[len|0] !== sValue) {
       return true; // preserve the value at this index
    } else {
       return false; // eliminate the value at this index
    }
  };
}

Please see my other post herefor more details on the binary search algorithim used

请参阅我的其他职位在这里对二进制搜索algorithim使用的细节,

If you are squeamish about file size like I am, then you can sacrifice some performance in order to greatly reduce the file size and increase maintainability.

如果你像我一样对文件大小很挑剔,那么你可以牺牲一些性能来大大减小文件大小并提高可维护性。

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }

function filterArrayByAnotherArray(searchArray, filterArray) {
    if (
        // NOTE: This does not check the whole array. But, if you know
        //        that there are only strings or numbers (not a mix of
        //        both) in the array, then this is a safe assumption.
        typeof searchArray[0] == "number" &&
        typeof filterArray[0] == "number" &&
        (searchArray[0]|0) === searchArray[0] &&
        (filterArray[0]|0) === filterArray[0]
    ) {
        // if all entries in both arrays are integers
        searchArray.sort(sortIntArray);
        filterArray.sort(sortIntArray);
    } else {
        searchArray.sort(sortAnyArray);
        filterArray.sort(sortAnyArray);
    }
    // Progressive Linear Search
    var i = 0;
    return searchArray.filter(function(currentValue){
        while (filterArray[i] < currentValue) i=i+1|0;
        // +undefined = NaN, which is always false for <, avoiding an infinite loop
        return filterArray[i] !== currentValue;
    });
}

To prove the difference in speed, let us examine some JSPerfs. For filtering an array of 16 elements, binary search is roughly 17% faster than indexOf while filterArrayByAnotherArray is roughly 93% faster than indexOf. For filtering an array of 256 elements, binary search is roughly 291% faster than indexOf while filterArrayByAnotherArray is roughly 353% faster than indexOf. For filtering an array of 4096 elements, binary search is roughly 2655% faster than indexOf while filterArrayByAnotherArray is roughly 4627% faster than indexOf.

为了证明速度上的差异,让我们检查一些 JSPerfs。对于过滤 16 个元素的数组,二分查找比 indexOf 快大约 17%,而 filterArrayByAnotherArray 比 indexOf 快大约 93%。对于过滤 256 个元素的数组,二分查找比 indexOf 快大约 291%,而 filterArrayByAnotherArray 比 indexOf 快大约 353%。对于过滤 4096 个元素的数组,二分查找比 indexOf 快大约 2655%,而 filterArrayByAnotherArray 比 indexOf 快大约 4627%。

回答by Hemadri Dasari

The OA can also be implemented in ES6 as follows

OA 也可以在 ES6 中实现如下

ES6:

ES6:

 const filtered = [1, 2, 3, 4].filter(e => {
    return this.indexOf(e) < 0;
  },[2, 4]);

回答by hypemichael

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>

回答by hypemichael

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>