วิธีกรองอาร์เรย์จากองค์ประกอบทั้งหมดของอาร์เรย์อื่น


160


ฉันต้องการที่จะเข้าใจวิธีที่ดีที่สุดที่จะกรองอาร์เรย์จากองค์ประกอบทั้งหมดของอีกคนหนึ่ง ฉันลองใช้ฟังก์ชั่นตัวกรอง แต่มันไม่ได้มาให้ฉันว่าจะให้ค่าที่ฉันต้องการลบได้อย่างไร
สิ่งที่ต้องการ:

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

ในกรณีที่ฟังก์ชันตัวกรองไม่เป็นประโยชน์คุณจะใช้สิ่งนี้อย่างไร
แก้ไข: ฉันตรวจสอบคำถามที่อาจซ้ำกันแล้วและอาจเป็นประโยชน์สำหรับผู้ที่เข้าใจจาวาสคริปต์ได้ง่าย คำตอบที่ตรวจสอบแล้วว่าดีทำให้สิ่งต่างๆง่ายขึ้น


8
ส่งอาร์เรย์อื่นเพื่อกรองการโทรกลับและใช้return arrTwo.indexOf(e) === -1; รหัส: var filteredArr = firstArr.filter(el => secondArr.indexOf(el) === -1);
Tushar


อาร์เรย์ทั้งสองสั่งหรือไม่
Nina Scholz

อาร์เรย์ไม่ได้เรียงลำดับเช่นกันอาร์เรย์ที่สองมีจำนวนองค์ประกอบแบบสุ่ม
Koop4

คำตอบ:


157

คุณสามารถใช้thisพารามิเตอร์ของfilter()ฟังก์ชันเพื่อหลีกเลี่ยงการจัดเก็บอาร์เรย์ตัวกรองของคุณในตัวแปรส่วนกลาง

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


มันใช้งานได้เหมือนมีเสน่ห์ เป็นไปได้ไหมที่จะย้ายฟังก์ชันออกไปข้างนอกและเรียกมันอย่างเข้าใจง่ายขึ้น? ชอบ: var กรอง = [1,2,3,4] .filter (myfunct (), [2,4]);
Koop4

1
แน่นอน: var myFunct = function (e) {return this.indexOf (e) <0;}; var กรอง = [1,2,3,4] .filter (myFunct, [2,4]);
Simon Hi

1
สิ่งนี้สามารถทำได้โดยใช้ lambda expression ใน ES2016 หรือ typesScript หรือไม่
Prabu


thisเมื่อฉันใช้วิธีนี้พระรามที่สองของตัวกรองไม่ได้ทำให้เป็นฟังก์ชั่นของฉันเป็น thisดูเหมือนจะไม่มีกำหนดเสมอ?! แปลก
บางสิ่งเมื่อ

174

ฉันจะทำดังนี้

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


6
ร็อคสตาร์. ขอบคุณนี่เป็นประโยชน์อย่างเหลือเชื่อสำหรับการแก้ปัญหาที่แตกต่างกันเล็กน้อย การกรองอาร์เรย์ของอ็อบเจ็กต์ตามอาร์เรย์ของค่าในองค์ประกอบปฏิกิริยา const filteredResults = this.state.cards.filter( result => !this.state.filterOut.includes(result.category) ) โดยที่ this.state.cards ในอาร์เรย์ของอ็อบเจ็กต์และ this.state.filterOut คืออาร์เรย์ของค่าที่สอดคล้องกับคีย์ 'หมวดหมู่' ในอ็อบเจ็กต์ที่ ฉันต้องการลบ
Josh Pittman

ฉันรู้ว่ามันเป็นคำตอบที่เก่ากว่า แต่ฉันแค่อยากบอกให้คุณรู้ว่าฉันชอบคำตอบนี้มากกว่านี้มากและมันช่วยฉันแก้ปัญหาของฉันได้ มันอ่านง่ายมากและทำให้ฉันเข้าใจปัญหาได้ดีขึ้น
ak.leimrey

1
รวมถึงจะใช้งานได้จาก ES7 เท่านั้น หากคุณใช้ ES6 ให้ใช้โซลูชันที่ยอมรับ
rudrasiva86

1
ฟังก์ชั่น Arrow FTW ดีกว่าการโทรกลับโรงเรียนเก่า!
Davis Jones

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

อาร์เรย์ของวัตถุสาธิต

สาธิตอาร์เรย์ของวัตถุที่แตกต่างกันด้วย lodash


สวัสดีคุณสามารถขยายสิ่งนี้ในอาร์เรย์ของวัตถุได้หรือไม่? ฉันจะขอบคุณมันมาก
Roel

คุณใช้ Lodash หรือไม่?
AshBringer

ไม่ครับผมชอบใช้วิธีโทรกลับ
Roel

ดีครับมันใช้งานได้จริง แต่นอกเหนือจาก id ฉันจะกรองชื่ออื่น ๆ ได้อย่างไร
Roel

hummm ... คุณเพียงแค่ต้องมีการเปลี่ยนแปลงidในanotherOne_el.id == array_el.idกับสิ่งที่สำคัญที่คุณมีในวัตถุของคุณเอง คุณควรได้รับความรู้เกี่ยวกับอาร์เรย์และวัตถุในจาวาสคริปต์ซึ่งจะช่วยให้คุณเข้าใจคำตอบได้ดีขึ้น
AshBringer

31

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


สิ่งที่ฉันต้องการ ขอบคุณ
vikrantnegi

ฉันไม่แน่ใจว่ามันทำงานอย่างไร แต่มีการปรับแต่งเล็กน้อยและช่วยประหยัดทั้งวัน ขอบคุณ. มันจะมีประโยชน์มากถ้ามีคนอธิบายได้ว่ามันทำงานอย่างไร
Chirag Jain

@ChiragJain แจ้งให้เราทราบว่ามีอะไรสับสนและชี้แจงได้!
เดวิดอลันคอนดิต

ทางออกที่ชาญฉลาดและมีเหตุผลอย่างแท้จริง!
DevLoverUmar

15

โค้ดด้านล่างนี้เป็นวิธีที่ง่ายที่สุดในการกรองอาร์เรย์เทียบกับอาร์เรย์อื่น อาร์เรย์ทั้งสองสามารถมีวัตถุอยู่ภายในแทนค่าได้

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

เอาท์พุต: [3, 6]


8

มีคำตอบมากมายสำหรับคำถามของคุณ แต่ฉันไม่เห็นใครใช้ lambda expresion:

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

7

ทั้งหมดการแก้ปัญหาดังกล่าวข้างต้น "งาน" แต่น้อยกว่าที่ดีที่สุดสำหรับการทำงานและวิธีการทุกปัญหาในลักษณะเดียวกันซึ่งเป็นเส้นตรงค้นหารายการทั้งหมดในแต่ละจุดใช้Array.prototype.indexOfหรือArray.prototype.includes วิธีแก้ปัญหาที่เร็วกว่ามาก (เร็วกว่าการค้นหาแบบไบนารีในกรณีส่วนใหญ่) คือการจัดเรียงอาร์เรย์และข้ามไปข้างหน้าตามที่แสดงด้านล่าง อย่างไรก็ตามข้อเสียอย่างหนึ่งคือสิ่งนี้ต้องการให้รายการทั้งหมดในอาร์เรย์เป็นตัวเลขหรือสตริง อย่างไรก็ตามในบางกรณีการค้นหาแบบไบนารีอาจเร็วกว่าการค้นหาเชิงเส้นแบบก้าวหน้า กรณีเหล่านี้เกิดขึ้นจากการที่การค้นหาเชิงเส้นแบบก้าวหน้าของฉันมีความซับซ้อนของO (2n 1 + n 2 ) (เฉพาะO (n 1+ n 2 ) n 2คืออาร์เรย์ตัวกรอง) ในขณะที่การค้นหาแบบไบนารีมีความซับซ้อนของO (n 1 ceil (log 2 n 2 )) ( ceil = ปัดเศษขึ้น - ไปที่เพดานใน ) และสุดท้ายดัชนีของการค้นหามีความซับซ้อนที่ผันแปรได้สูงระหว่างO (n 1 )และO (n 1 n 2 )โดยเฉลี่ยออกเป็นO (n 1 ceil (n 2) ÷ 2)) . ดังนั้น indexOf จะเร็วที่สุดโดยเฉลี่ยในกรณีของในเวอร์ชัน C / C ++ ที่เร็วกว่า) (โดยที่n 1คืออาร์เรย์ที่ค้นหาและ(n 1 , n 2 )เท่ากับ{1,2} , {1,3}หรือ{x 1 | x∈N} อย่างไรก็ตามนี่ยังไม่ใช่การนำเสนอฮาร์ดแวร์สมัยใหม่ที่สมบูรณ์แบบ IndexOf มีการเพิ่มประสิทธิภาพในการกำเนิดเท่าที่ขอบเขตในเบราว์เซอร์ที่ทันสมัยที่สุดทำให้มันมากภายใต้กฎหมายของการทำนายสาขา ดังนั้นหากเราตั้งสมมติฐานเดียวกันกับ indexOf เหมือนกับที่เราทำกับการค้นหาเชิงเส้นและไบนารีแบบโปรเกรสซีฟนั่นคืออาร์เรย์ถูกกำหนดไว้ล่วงหน้าแล้วตามสถิติที่ระบุไว้ในลิงก์เราสามารถคาดหวังว่า IndexOf จะเร็วขึ้น 6 เท่า เปลี่ยนความซับซ้อนไประหว่างO (n 1 ÷ 6)และO (n 1 n 2 )ค่าเฉลี่ยออกไปO (n 1 ceil (n 2 7 ÷ . สุดท้ายโปรดทราบว่าโซลูชันด้านล่างนี้จะไม่ทำงานกับอ็อบเจ็กต์เนื่องจากอ็อบเจ็กต์ใน JavaScript ไม่สามารถเปรียบเทียบด้วยพอยน์เตอร์ใน 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
    }
  };
}

โปรดดูโพสต์อื่น ๆ ของฉันที่นี่สำหรับรายละเอียดเพิ่มเติมเกี่ยวกับอัลกอริทึมการค้นหาแบบไบนารีที่ใช้

หากคุณรู้สึกแย่เกี่ยวกับขนาดไฟล์ (ซึ่งฉันเคารพ) คุณสามารถเสียสละประสิทธิภาพเพียงเล็กน้อยเพื่อลดขนาดไฟล์ลงอย่างมากและเพิ่มความสามารถในการบำรุงรักษา

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

เพื่อพิสูจน์ความแตกต่างของความเร็วให้เราตรวจสอบ JSPerfs สำหรับการกรองอาร์เรย์ 16 องค์ประกอบการค้นหาแบบไบนารีจะเร็วกว่า indexOf ประมาณ 17% ในขณะที่ filterArrayByAnotherArray เร็วกว่า indexOf ประมาณ 93% สำหรับการกรองอาร์เรย์ของ 256 องค์ประกอบการค้นหาไบนารีจะเร็วกว่า indexOf ประมาณ 291% ในขณะที่ filterArrayByAnotherArray เร็วกว่า indexOf ประมาณ 353% สำหรับการกรองอาร์เรย์ขององค์ประกอบ 4096ค้นหาไบนารีจะเร็วกว่า indexOf ประมาณ 2655% ในขณะที่ filterArrayByAnotherArray เร็วกว่า indexOf ประมาณ 4627%

การกรองย้อนกลับ (เช่นประตู AND)

ส่วนก่อนหน้านี้ระบุรหัสเพื่อรับอาร์เรย์ A และอาร์เรย์ B และลบองค์ประกอบทั้งหมดจาก A ที่มีอยู่ใน B:

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

ส่วนถัดไปนี้จะให้รหัสสำหรับการกรองย้อนกลับโดยที่เราจะลบองค์ประกอบทั้งหมดออกจาก A ที่ไม่มีอยู่ใน B กระบวนการนี้เทียบเท่ากับการรักษาเฉพาะองค์ประกอบทั่วไปของทั้ง A และ B เช่นประตู AND:

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

นี่คือรหัสสำหรับการกรองย้อนกลับ:

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]
    ) {
        // 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
    }
  };
}

สำหรับโค้ดการกรองย้อนกลับรุ่นเล็กที่ช้ากว่าโปรดดูด้านล่าง

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
ขอบคุณสำหรับคำตอบฉันแน่ใจว่าจะเป็นประโยชน์สำหรับใครบางคนไม่ช้าก็เร็วแม้ว่าควรใช้ในกรณีที่มีขอบ (IE เฉพาะเมื่อปัญหาด้านประสิทธิภาพเพิ่มขึ้น) ในกรณีอื่น ๆ ฉันขอแนะนำให้ใช้เวอร์ชันที่บำรุงรักษา / อ่านได้
Koop4

1
@JackGiffin ฉันคิดว่าโดยการอ่านได้เขาหมายถึงความสามารถในการใช้งานได้และรวดเร็วในการอ่านและทำความเข้าใจโดยนักพัฒนาเว็บโดยเฉลี่ยเมื่อจำเป็นต้องมีการเปลี่ยนแปลงหรือการวางรากฐานอย่างง่าย ทางออกที่ดีไม่ใช่สำหรับกรณีส่วนใหญ่
zardilior

1
การเพิ่มประสิทธิภาพในช่วงต้นของ @JackGiffin เป็นหนึ่งในสิ่งที่เลวร้ายที่สุดสำหรับโครงการควรใช้ประสิทธิภาพโดยทั่วไปในรูปแบบต่างๆการเขียนโค้ดที่มีประสิทธิภาพถ้าง่ายพอหมายความว่าอย่าเขียนตรงผ่านโค้ดที่ไม่ดีและเมื่อจำเป็นต้องมีการเพิ่มประสิทธิภาพเนื่องจากประสิทธิภาพไม่ตรงตามข้อกำหนด . ดังนั้นคนอย่างคุณควรทำงานเพื่อเพิ่มประสิทธิภาพโครงการอื่น ๆ ที่ต้องการทักษะที่ได้รับจากการครอบงำจิตใจ หวังว่าจะช่วยได้ :)
zardilior

1
@zardilior มันช่วยได้จริงๆ ขอบคุณมากสำหรับคำแนะนำของคุณ zardilior ฉันจะทำใจและลงมือทำ
Jack Giffin

1
@JackGiffin ยินดีให้บริการ
zardilior

3

OA สามารถนำไปใช้ใน ES6 ได้ดังนี้

ES6:

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

นอกเหนือจากไวยากรณ์ของลูกศรแล้ว ES6 จะมีข้อดีอะไรบ้างในการกรอง
Carl Edwards

2

หากคุณต้องการเปรียบเทียบอาร์เรย์ของวัตถุสิ่งนี้ใช้ได้ในทุกกรณี:

let arr = [{ id: 1, title: "title1" },{ id: 2, title: "title2" }]
let brr = [{ id: 2, title: "title2" },{ id: 3, title: "title3" }]

const res = arr.filter(f => brr.some(item => item.id === f.id));
console.log(res);

1

คำอธิบายที่ดีที่สุดในการ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);

และคุณไม่สามารถเข้าถึงค่าตัวแปรก่อนกำหนดได้


1

คุณสามารถตั้งค่าฟังก์ชันตัวกรองเพื่อวนซ้ำบน "อาร์เรย์ตัวกรอง"

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

คุณสามารถใช้ตัวกรองจากนั้นสำหรับฟังก์ชันตัวกรองให้ใช้การลดอาร์เรย์การกรองซึ่งตรวจสอบและส่งคืนค่าจริงเมื่อพบการจับคู่จากนั้นกลับด้านกลับ (!) ฟังก์ชันตัวกรองถูกเรียกหนึ่งครั้งต่อองค์ประกอบในอาร์เรย์ คุณไม่ได้ทำการเปรียบเทียบองค์ประกอบใด ๆ ในฟังก์ชันในโพสต์ของคุณ

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>


ขอบคุณมันใช้งานได้ แต่ฉันต้องการรักษาขอบเขตท้องถิ่นไว้ นอกจากนี้ arr2 ยังมีจำนวนองค์ประกอบแบบสุ่ม
Koop4


1

อาร์เรย์การกรองที่ยืดหยุ่นมากขึ้นจากอาร์เรย์อื่นซึ่งมีคุณสมบัติของวัตถุ

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

คุณสามารถเขียนฟังก์ชัน 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]

1

ตัวอย่างต่อไปนี้ใช้ new Set()เพื่อสร้างอาร์เรย์กรองที่มีเฉพาะองค์ประกอบที่ไม่ซ้ำกัน:

อาร์เรย์ที่มีชนิดข้อมูลดั้งเดิม: สตริง, ตัวเลข, บูลีน, โมฆะ, ไม่ได้กำหนด, สัญลักษณ์:

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


0

วิธีแก้ปัญหาของ Jack Giffin นั้นยอดเยี่ยม แต่ใช้ไม่ได้กับอาร์เรย์ที่มีตัวเลขมากกว่า 2 ^ 32 ด้านล่างนี้เป็นเวอร์ชันที่ปรับโครงสร้างใหม่และรวดเร็วเพื่อกรองอาร์เรย์ตามโซลูชันของ Jack แต่ใช้ได้กับอาร์เรย์ 64 บิต

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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.