Cách lọc một mảng từ tất cả các thành phần của mảng khác


139


Tôi muốn hiểu cách tốt nhất để lọc một mảng từ tất cả các thành phần của một mảng khác . Tôi đã thử với chức năng lọc, nhưng tôi không biết cách cung cấp cho nó các giá trị tôi muốn xóa.
Cái gì đó như:

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

trong trường hợp chức năng lọc không hữu ích, bạn sẽ thực hiện việc này như thế nào?
Chỉnh sửa: tôi đã kiểm tra câu hỏi trùng lặp có thể và nó có thể hữu ích cho những người hiểu javascript một cách dễ dàng. Câu trả lời là tốt làm cho mọi thứ dễ dàng.


8
Vượt qua mảng khác để lọc gọi lại và sử dụng return arrTwo.indexOf(e) === -1; Mã: var filteredArr = firstArr.filter(el => secondArr.indexOf(el) === -1);
Tushar


cả hai mảng được đặt hàng?
Nina Scholz

mảng không được sắp xếp, ngoài ra, mảng thứ hai có số phần tử ngẫu nhiên.
Koop4

Câu trả lời:


145

Bạn có thể sử dụng thistham số của filter()hàm để tránh lưu trữ mảng bộ lọc của mình trong một biến toàn cục.

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


Nó hoạt động như một say mê. Có thể di chuyển các chức năng bên ngoài và gọi nó theo một cách dễ hiểu hơn? Giống như: var được lọc = [1,2,3,4] .filter (myfunc (), [2,4]);
Koop4

1
Chắc chắn: var myFunc = function (e) {return this.indexOf (e) <0;}; var được lọc = [1,2,3,4] .filter (myFunc, [2,4]);
Simon Hi

1
Điều này có thể đạt được với biểu thức lambda trong ES2016 hoặc FormsScript không?
Mitchu


Khi tôi sử dụng phương pháp này, thông số thứ hai của bộ lọc không biến nó thành chức năng của tôi như this. thisdường như luôn luôn không được xác định?! Lạ
Một cái gì đó vào

147

Tôi sẽ làm như sau;

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


6
Ngôi sao nhạc rock. Cảm ơn bạn, điều này cực kỳ hữu ích để giải quyết một vấn đề hơi khác. Lọc ra một mảng các đối tượng dựa trên một mảng các giá trị trong thành phần phản ứng: const filteredResults = this.state.cards.filter( result => !this.state.filterOut.includes(result.category) ) trong đó this.state.cards trong một mảng các đối tượng và this.state.filterOut là một mảng các giá trị tương ứng với khóa 'thể loại' trong các đối tượng Tôi muốn loại bỏ.
Josh Pittman

Tôi biết, đó là một phản hồi cũ hơn, nhưng tôi chỉ đơn giản muốn cho bạn biết rằng tôi thích phản hồi này hơn rất nhiều và nó đã giúp tôi với một trong những vấn đề tôi gặp phải. Nó rất dễ đọc và do đó tôi dễ hiểu vấn đề hơn.
ak.leimrey

1
bao gồm sẽ chỉ hoạt động từ ES7. Nếu bạn sử dụng ES6, hãy sử dụng giải pháp được chấp nhận.
rudrasiva86

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

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

Trong cuộc gọi lại, bạn kiểm tra xem mỗi giá trị của array là tronganotherOne

https://jsfiddle.net/0tsyc1sx/

Nếu bạn đang sử dụng lodash.js, sử dụng_.difference

filteredArray = _.difference(array, anotherOne);

Bản giới thiệu

Nếu bạn có một mảng các đối tượng:

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
});

Mảng demo của các đối tượng

Demo mảng khác của đối tượng với lodash


Xin chào, bạn có thể mở rộng cái này trong mảng các đối tượng không? tôi sẽ đánh giá cao nó
Roel

Bạn đang sử dụng lodash?
AshBringer

Không thưa ông, tôi thích làm theo phương thức gọi lại
Roel

Vâng, nó thực sự đã làm việc nhưng ngoài id, làm thế nào tôi có thể lọc tên khác?
Roel

Hummm ... Bạn chỉ cần thay đổi idtrong anotherOne_el.id == array_el.idvới bất cứ chìa khóa bạn có trong đối tượng của riêng bạn. Bạn nên tìm hiểu kiến ​​thức về mảng và đối tượng trong javascript, nó sẽ giúp bạn hiểu rõ hơn câu trả lời
AshBringer

26

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


Chính xác những gì tôi cần. Cảm ơn
vikrantnegi

12

Mã dưới đây là cách đơn giản nhất để lọc một mảng đối với mảng khác. Cả hai mảng có thể có các đối tượng bên trong chúng thay vì các giá trị.

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

Đầu ra: [3, 6]


8

Có rất nhiều câu trả lời cho câu hỏi của bạn, nhưng tôi không thấy ai sử dụng lambda expresion:

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

6

Tất cả các giải pháp trên "hoạt động", nhưng ít hơn tối ưu cho hiệu suất và đều tiếp cận vấn đề theo cùng một cách tìm kiếm tuyến tính tất cả các mục tại mỗi điểm bằng Array.prototype.indexOf hoặc Array.prototype.includes . Một giải pháp nhanh hơn nhiều (nhanh hơn nhiều so với tìm kiếm nhị phân trong hầu hết các trường hợp) sẽ là sắp xếp các mảng và bỏ qua phía trước khi bạn đi theo như được thấy dưới đây. Tuy nhiên, một nhược điểm là điều này đòi hỏi tất cả các mục trong mảng phải là số hoặc chuỗi. Tuy nhiên, trong một số trường hợp hiếm hoi, tìm kiếm nhị phân có thể nhanh hơn tìm kiếm tuyến tính lũy tiến. Những trường hợp này phát sinh từ thực tế là tìm kiếm tuyến tính lũy tiến của tôi có độ phức tạp là O (2n 1 + n 2 ) (chỉ O (n 1+ n 2 ) trong phiên bản C / C ++ nhanh hơn) (trong đó n 1 là mảng được tìm kiếm và n 2 là mảng bộ lọc), trong khi tìm kiếm nhị phân có độ phức tạp là O (n 1 ceil (log 2 n 2 )) ( ceil = làm tròn lên - đến trần nhà ) và cuối cùng, tìm kiếm indexOf có độ phức tạp biến đổi cao giữa O (n 1 ) O (n 1 n 2 ) , tính trung bình cho O (n 1 ceil (n 2) ÷ 2)) . Do đó, indexOf sẽ chỉ nhanh nhất, trung bình, trong các trường hợp(n 1 , n 2 ) bằng ){1,2} , {1,3} hoặc {x, 1 | x∈N} . Tuy nhiên, đây vẫn không phải là một đại diện hoàn hảo của phần cứng hiện đại. IndexOf thực sự được tối ưu hóa đến mức tối đa có thể tưởng tượng trong hầu hết các trình duyệt hiện đại, khiến nó rất tuân theo luật dự đoán chi nhánh . Do đó, nếu chúng ta đưa ra giả định tương tự trên indexOf như chúng ta thực hiện với tìm kiếm tuyến tính và nhị phân lũy tiến - rằng mảng được đặt trước - thì, theo các số liệu thống kê được liệt kê trong liên kết, chúng ta có thể mong đợi tốc độ tăng gấp 6 lần cho IndexOf, chuyển độ phức tạp của nó sang giữa O (n 1 6)O (n 1 n 2 , tính trung bình cho O (n 1 trần (n 2 7 12)) . Cuối cùng, hãy lưu ý rằng giải pháp bên dưới sẽ không bao giờ hoạt động với các đối tượng vì các đối tượng trong JavaScript không thể được so sánh bằng các con trỏ trong JavaScript.

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
    var out=[], value=0;
    for (var i=0,  len=array.length|0; i < len; i=i+1|0)
        if (handle(value = array[i])) 
            out.push( value );
    return out;
}

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

/* USAGE:
  filterArrayByAnotherArray(
      [1,3,5],
      [2,3,4]
  ) yields [1, 5], and it can work with strings too
*/
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 fastFilter(searchArray, 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 fastFilter(
            searchArray,
            fastestBinarySearch(filterArray)
        );
    }
}

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

function fastestBinarySearch(array){
  var initLen = (array.length|0) - 1 |0;
  
  const compGoto = Math_clz32(initLen) & 31;
  return function(sValue) {
    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
    }
  };
}

Vui lòng xem bài viết khác của tôi ở đây để biết thêm chi tiết về thuật toán tìm kiếm nhị phân được sử dụng

Nếu bạn không hài lòng về kích thước tệp (mà tôi tôn trọng), thì bạn có thể hy sinh một chút hiệu suất để giảm đáng kể kích thước tệp và tăng khả năng bảo trì.

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
    var out=[], value=0;
    for (var i=0,  len=array.length|0; i < len; i=i+1|0)
        if (handle(value = array[i])) 
            out.push( value );
    return out;
}

/* USAGE:
  filterArrayByAnotherArray(
      [1,3,5],
      [2,3,4]
  ) yields [1, 5], and it can work with strings too
*/
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 fastFilter(searchArray, 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;
    });
}

Để chứng minh sự khác biệt về tốc độ, chúng ta hãy kiểm tra một số tệp JSPerfs. Để lọc một mảng gồm 16 phần tử , tìm kiếm nhị phân nhanh hơn khoảng 17% so với indexOf trong khi bộ lọcArrayByAnotherArray nhanh hơn khoảng 93% so với indexOf. Để lọc một mảng gồm 256 phần tử , tìm kiếm nhị phân nhanh hơn khoảng 29% so với indexOf trong khi bộ lọcArrayByAnotherArray nhanh hơn khoảng 353% so với indexOf. Để lọc một mảng gồm 4096 phần tử , tìm kiếm nhị phân nhanh hơn khoảng 2655% so với indexOf trong khi bộ lọcArrayByAnotherArray nhanh hơn khoảng 4627% so với indexOf.

Lọc ngược (như cổng AND)

Phần trước đã cung cấp mã để lấy mảng A và mảng B và loại bỏ tất cả các phần tử khỏi A tồn tại trong B:

filterArrayByAnotherArray(
    [1,3,5],
    [2,3,4]
);
// yields [1, 5]

Phần tiếp theo này sẽ cung cấp mã để lọc ngược, trong đó chúng tôi loại bỏ tất cả các phần tử khỏi A mà KHÔNG tồn tại trong B. Quá trình này có chức năng tương đương với việc chỉ giữ lại các phần tử phổ biến cho cả A và B, như cổng AND:

reverseFilterArrayByAnotherArray(
    [1,3,5],
    [2,3,4]
);
// yields [3]

Đây là mã để lọc ngược:

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
    var out=[], value=0;
    for (var i=0,  len=array.length|0; i < len; i=i+1|0)
        if (handle(value = array[i])) 
            out.push( value );
    return out;
}

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

/* USAGE:
  reverseFilterArrayByAnotherArray(
      [1,3,5],
      [2,3,4]
  ) yields [3], and it can work with strings too
*/
function reverseFilterArrayByAnotherArray(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 fastFilter(searchArray, function(currentValue){
            while (filterArray[i] < currentValue) i=i+1|0;
            // +undefined = NaN, which is always false for <, avoiding an infinite loop
            // For reverse filterning, I changed !== to ===
            return filterArray[i] === currentValue;
        });
    } else {
        // Binary Search
        return fastFilter(
            searchArray,
            inverseFastestBinarySearch(filterArray)
        );
    }
}

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

function inverseFastestBinarySearch(array){
  var initLen = (array.length|0) - 1 |0;
  
  const compGoto = Math_clz32(initLen) & 31;
  return function(sValue) {
    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.
    // For reverse filterning, I swapped true with false and vice-versa
    if (array[len|0] !== sValue) {
       return false; // preserve the value at this index
    } else {
       return true; // eliminate the value at this index
    }
  };
}

Đối với phiên bản nhỏ hơn chậm hơn của mã lọc ngược, xem bên dưới.

function sortAnyArray(a,b) { return a>b ? 1 : (a===b ? 0 : -1); }
function sortIntArray(a,b) { return (a|0) - (b|0) |0; }
function fastFilter(array, handle) {
    var out=[], value=0;
    for (var i=0,  len=array.length|0; i < len; i=i+1|0)
        if (handle(value = array[i])) 
            out.push( value );
    return out;
}

/* USAGE:
  reverseFilterArrayByAnotherArray(
      [1,3,5],
      [2,3,4]
  ) yields [3], and it can work with strings too
*/
function reverseFilterArrayByAnotherArray(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 fastFilter(searchArray, function(currentValue){
        while (filterArray[i] < currentValue) i=i+1|0;
        // +undefined = NaN, which is always false for <, avoiding an infinite loop
        // For reverse filter, I changed !== to ===
        return filterArray[i] === currentValue;
    });
}

4
Cảm ơn câu trả lời của bạn, tôi chắc chắn sẽ hữu ích cho ai đó sớm hay muộn, ngay cả khi nó nên được sử dụng trong các trường hợp cạnh (chỉ IE khi có vấn đề về hiệu suất tăng lên). Trong tất cả các trường hợp khác, tôi khuyên bạn nên sử dụng phiên bản có thể duy trì / có thể đọc được.
Koop4

1
@JackGiffin Tôi nghĩ rằng bằng cách đọc được, anh ta có nghĩa là có thể đọc được và hiểu nhanh bởi nhà phát triển web trung bình, vì khi cần một thay đổi hoặc đơn giản là cần thiết. Giải pháp tuyệt vời, chỉ không cho hầu hết các trường hợp.
zardilior

1
Tối ưu hóa sớm @JackGiffin là một trong những điều tồi tệ nhất đối với các dự án, hiệu suất thường được áp dụng theo cách, viết mã hiệu quả, nếu đủ đơn giản, nghĩa là không viết thẳng qua mã xấu và khi cần tối ưu hóa vì hiệu suất không đáp ứng yêu cầu . Vì vậy, một người như bạn nên làm việc tối ưu hóa các dự án khác cần kỹ năng bắt nguồn ám ảnh đó. Hy vọng nó sẽ giúp :)
zardilior

1
@zardilior Nó thực sự có ích. Cảm ơn bạn rất nhiều vì lời khuyên của bạn zardilior. Tôi sẽ mang nó đến trái tim và hành động theo nó.
Jack Giffin

1
@JackGiffin rất vui khi được phục vụ
zardilior

3

OA cũng có thể được thực hiện trong ES6 như sau

ES6:

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

Ngoài cú pháp mũi tên, giải pháp ES6 này có lợi thế gì khi lọc?
Carl Edwards


1

Bạn có thể thiết lập chức năng lọc để lặp qua "mảng bộ lọc".

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;
  }
); 

1

Bạn có thể sử dụng bộ lọc và sau đó cho chức năng bộ lọc sử dụng việc giảm mảng lọc sẽ kiểm tra và trả về giá trị true khi tìm thấy kết quả khớp sau đó đảo ngược khi trả về (!). Hàm bộ lọc được gọi một lần cho mỗi phần tử trong mảng. Bạn không làm một so sánh về bất kỳ yếu tố nào trong chức năng trong bài viết của bạn.

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


1

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>


Cảm ơn, nó hoạt động, nhưng tôi muốn giữ phạm vi địa phương. Ngoài ra, Array2 có số lượng phần tử ngẫu nhiên.
Koop4

1

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>


1

Một mảng lọc linh hoạt hơn từ một mảng khác có chứa các thuộc tính đối tượng

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)


1

Bạn có thể viết hàm bộ lọc chungByIndex () và sử dụng suy luận kiểu trong TS để lưu rắc rối với hàm gọi lại:

giả sử bạn có mảng [1,2,3,4] mà bạn muốn lọc () với các chỉ số được chỉ định trong mảng [2,4].

var filtered = [1,2,3,4,].filter(byIndex(element => element, [2,4]))

hàm byIndex mong đợi hàm phần tử và một mảng và trông như thế này:

byIndex = (getter: (e:number) => number, arr: number[]) => (x: number) => {
    var i = getter(x);
    return arr.indexOf(i); 
}

kết quả là sau đó

filtered = [1,3]

1

Các ví dụ sau sử dụng new Set()để tạo một mảng được lọc chỉ có các phần tử duy nhất:

Mảng với các kiểu dữ liệu nguyên thủy: chuỗi, số, boolean, null, không xác định, ký hiệu:

const a = [1, 2, 3, 4];
const b = [3, 4, 5];
const c = Array.from(new Set(a.concat(b)));

Mảng với các đối tượng là các mục:

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

1

Dưới đây là một ví dụ

let firstArray=[1,2,3,4,5];
let secondArray=[2,3];  
let filteredArray = firstArray.filter((a) => secondArray.indexOf(a)<0);
console.log(filteredArray); //above line gives [1,4,5]


0

Giải pháp của Jack Giffin là tuyệt vời nhưng không hoạt động đối với các mảng có số lớn hơn 2 ^ 32. Dưới đây là phiên bản nhanh, được tái cấu trúc để lọc một mảng dựa trên giải pháp của Jack nhưng nó hoạt động cho các mảng 64 bit.

const Math_clz32 = Math.clz32 || ((log, LN2) => x => 31 - log(x >>> 0) / LN2 | 0)(Math.log, Math.LN2);

const filterArrayByAnotherArray = (searchArray, filterArray) => {

    searchArray.sort((a,b) => a > b);
    filterArray.sort((a,b) => a > b);

    let searchArrayLen = searchArray.length, filterArrayLen = filterArray.length;
    let progressiveLinearComplexity = ((searchArrayLen<<1) + filterArrayLen)>>>0
    let binarySearchComplexity = (searchArrayLen * (32-Math_clz32(filterArrayLen-1)))>>>0;

    let i = 0;

    if (progressiveLinearComplexity < binarySearchComplexity) {
      return searchArray.filter(currentValue => {
        while (filterArray[i] < currentValue) i=i+1|0;
        return filterArray[i] !== currentValue;
      });
    }
    else return searchArray.filter(e => binarySearch(filterArray, e) === null);
}

const binarySearch = (sortedArray, elToFind) => {
  let lowIndex = 0;
  let highIndex = sortedArray.length - 1;
  while (lowIndex <= highIndex) {
    let midIndex = Math.floor((lowIndex + highIndex) / 2);
    if (sortedArray[midIndex] == elToFind) return midIndex; 
    else if (sortedArray[midIndex] < elToFind) lowIndex = midIndex + 1;
    else highIndex = midIndex - 1;
  } return null;
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.