ลบองค์ประกอบทั้งหมดที่มีอยู่ในอาร์เรย์อื่น


222

ฉันกำลังมองหาวิธีที่มีประสิทธิภาพในการลบองค์ประกอบทั้งหมดออกจากอาร์เรย์ JavaScript หากมีอยู่ในอาร์เรย์อื่น

// If I have this array:
var myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

// and this one:
var toRemove = ['b', 'c', 'g'];

ฉันต้องการทำงานกับ myArray เพื่อปล่อยให้อยู่ในสถานะนี้: ['a', 'd', 'e', 'f']

ด้วย jQuery ฉันใช้grep()และใช้inArray()งานได้ดี:

myArray = $.grep(myArray, function(value) {
    return $.inArray(value, toRemove) < 0;
});

มีวิธีจาวาสคริปต์ที่บริสุทธิ์ในการทำเช่นนี้โดยไม่ต้องวนและต่อ?


1
เป็นไปได้ที่ซ้ำกันของการลบองค์ประกอบเฉพาะจากอาร์เรย์?
mplungjan

4
อาจมีความซ้ำซ้อนของอาร์เรย์ JavaScript
Explosion Pills

1
เป็นไปได้ที่ซ้ำกันของคุณสามารถลบหนึ่งอาเรย์จากใน javascript หรือ jquery - คุณไม่ได้ให้ความสนใจมากกับคำแนะนำที่ทำเมื่อคุณเขียนคำถาม
mplungjan

ไม่ว่าจะเกิดอะไรขึ้นมันจะเกี่ยวข้องกับการวนซ้ำในบางระดับเสมอ
Blue Skies

ถ้าคุณอย่างแท้จริงต้องการให้เป็น "ที่มีประสิทธิภาพ" .filter()คุณจะไม่ใช้วิธีการประเภทการทำงานเช่น แต่คุณจะใช้forลูปแทน คุณสามารถหลีกเลี่ยงได้.splice()หากไม่จำเป็นต้องรักษาคำสั่งซื้อดั้งเดิมไว้ หรือมีวิธีที่จะทำให้.splice()มีประสิทธิภาพมากขึ้นถ้าคุณคิดว่าจะมีหลายรายการที่จะลบ
Blue Skies

คำตอบ:


379

ใช้Array.filter()วิธีการ:

myArray = myArray.filter( function( el ) {
  return toRemove.indexOf( el ) < 0;
} );

การปรับปรุงเล็กน้อยเนื่องจากการสนับสนุนเบราว์เซอร์สำหรับArray.includes()เพิ่มขึ้น:

myArray = myArray.filter( function( el ) {
  return !toRemove.includes( el );
} );

การปรับตัวครั้งต่อไปโดยใช้ฟังก์ชั่นลูกศร :

myArray = myArray.filter( ( el ) => !toRemove.includes( el ) );

23
OP: ถ้าคุณใช้Underscore.jsนั่นก็คือ.difference()สิ่งนี้
Bill Criswell

สิ่งที่ฉันกำลังมองหา ขอบคุณ. @BillCriswell ฉันจะตรวจสอบขีดล่าง
แตะ

1
@AlecRust แปลงองค์ประกอบทั้งหมดของtoRemove()กรณีบนและการเปลี่ยนแปลงในการเรียกกลับจากไปel el.toUpperCase()
Sirko

5
หรือสั้นกว่า:myArray = myArray.filter( el => !toRemove.includes( el ) );
538ROMEO

1
ใบสั่งนี้ไม่ใช่ ^^ หรือไม่
Frazer Kirkman

34

filterวิธีควรทำเคล็ดลับ:

const myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
const toRemove = ['b', 'c', 'g'];

// ES5 syntax
const filteredArray = myArray.filter(function(x) { 
  return toRemove.indexOf(x) < 0;
});

หากtoRemoveอาร์เรย์ของคุณมีขนาดใหญ่รูปแบบการค้นหาเช่นนี้อาจไม่มีประสิทธิภาพ มันจะ performant มากขึ้นเพื่อสร้างแผนที่เพื่อการค้นหาที่มีมากกว่าO(1)O(n)

const toRemoveMap = toRemove.reduce(
  function(memo, item) {
    memo[item] = memo[item] || true;
    return memo;
  },
  {} // initialize an empty object
);

const filteredArray = myArray.filter(function (x) {
  return toRemoveMap[x];
});

// or, if you want to use ES6-style arrow syntax:
const toRemoveMap = toRemove.reduce((memo, item) => ({
  ...memo,
  [item]: true
}), {});

const filteredArray = myArray.filter(x => toRemoveMap[x]);

24

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

ในตัวอย่างด้านล่างรายการที่ซ้ำกันจะถูกลบออกเปรียบเทียบชื่อของแต่ละรายการ

ลองตัวอย่างนี้ http://jsfiddle.net/deepak7641/zLj133rh/

var myArray = [
  {name: 'deepak', place: 'bangalore'}, 
  {name: 'chirag', place: 'bangalore'}, 
  {name: 'alok', place: 'berhampur'}, 
  {name: 'chandan', place: 'mumbai'}
];
var toRemove = [
  {name: 'deepak', place: 'bangalore'},
  {name: 'alok', place: 'berhampur'}
];

for( var i=myArray.length - 1; i>=0; i--){
 	for( var j=0; j<toRemove.length; j++){
 	    if(myArray[i] && (myArray[i].name === toRemove[j].name)){
    		myArray.splice(i, 1);
    	}
    }
}

alert(JSON.stringify(myArray));



11

ECMAScript 6 ชุดสามารถใช้สำหรับการคำนวณองค์ประกอบต่าง ๆ ของสองอาร์เรย์:

const myArray = new Set(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
const toRemove = new Set(['b', 'c', 'g']);

const difference = new Set([...myArray].filter((x) => !toRemove.has(x)));

console.log(Array.from(difference)); // ["a", "d", "e", "f"]


8

ฉันเพิ่งใช้งานเป็น:

Array.prototype.exclude = function(list){
        return this.filter(function(el){return list.indexOf(el)<0;})
}

ใช้เป็น:

myArray.exclude(toRemove);

1
มันไม่ใช่แนวปฏิบัติที่ดีในการขยายprototypesวัตถุดั้งเดิมเช่นArrayนั้น ที่อาจมีความขัดแย้งในระยะยาวกับการพัฒนาภาษาในอนาคต ( ดูflattenกรณี )
MarcoL

6

หากคุณไม่สามารถใช้สิ่ง ES5 ใหม่เช่นfilterฉันคิดว่าคุณติดอยู่กับสองลูป:

for( var i =myArray.length - 1; i>=0; i--){
  for( var j=0; j<toRemove.length; j++){
    if(myArray[i] === toRemove[j]){
      myArray.splice(i, 1);
    }
  }
}

ตัวกรองไม่ใช่ "สิ่ง HTML5 ใหม่"
goofballLogic

ฉันควรจะเขียน "สิ่ง ES5" ไม่สามารถใช้ได้กับ ES3
MarcoL

6
var myArray = [
  {name: 'deepak', place: 'bangalore'}, 
  {name: 'chirag', place: 'bangalore'}, 
  {name: 'alok', place: 'berhampur'}, 
  {name: 'chandan', place: 'mumbai'}
];
var toRemove = [
  {name: 'deepak', place: 'bangalore'},
  {name: 'alok', place: 'berhampur'}
];



myArray = myArray.filter(ar => !toRemove.find(rm => (rm.name === ar.name && ar.place === rm.place) ))

คุณต้องการเพิ่มคำอธิบายสำหรับคำถามที่ได้รับการตอบรับดีไหม
harmonica141

1
ฉันค้นหาเวลาหลายชั่วโมงเพื่อหาวิธีแก้ปัญหาและพบว่ามันยอดเยี่ยมมาก ขอบคุณมาก!
Tarvo Mäesepp


3

คุณสามารถใช้_.differenceByจาก lodash

const myArray = [
  {name: 'deepak', place: 'bangalore'}, 
  {name: 'chirag', place: 'bangalore'}, 
  {name: 'alok', place: 'berhampur'}, 
  {name: 'chandan', place: 'mumbai'}
];
const toRemove = [
  {name: 'deepak', place: 'bangalore'},
  {name: 'alok', place: 'berhampur'}
];
const sorted = _.differenceBy(myArray, toRemove, 'name');

โค้ดตัวอย่างที่นี่: CodePen


จะเกิดอะไรขึ้นถ้าแอตทริบิวต์นั้นซ้อนอยู่ภายในวัตถุ การทดสอบบางอย่างเช่นในกรณีของคุณ {ชื่อ: 'deepak', สถานที่: 'bangalore', ซ้อนกัน: {test: 1}}
Charith Jayasanka

2

วิธีที่ง่ายที่สุดที่เป็นไปได้:

var myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
var toRemove = ['b', 'c', 'g'];

var myArray = myArray.filter((item) => !toRemove.includes(item));
console.log(myArray)


2
โปรดทราบว่าincludesไม่พร้อมใช้งานก่อน ES7
เกร็ก

0

วิธีที่เหมาะสมในการลบองค์ประกอบทั้งหมดที่มีอยู่ในอาเรย์อื่นคือการทำให้ออบเจ็กต์อาร์เรย์เหมือนกันโดยการลบองค์ประกอบเท่านั้น:

Array.prototype.removeContained = function(array) {
  var i, results;
  i = this.length;
  results = [];
  while (i--) {
    if (array.indexOf(this[i]) !== -1) {
      results.push(this.splice(i, 1));
    }
  }
  return results;
};

หรือเทียบเท่า CoffeeScript:

Array.prototype.removeContained = (array) ->
  i = @length
  @splice i, 1 while i-- when array.indexOf(@[i]) isnt -1

การทดสอบเครื่องมือ Chrome dev:

19: 33: 04.447 a = 1
19: 33: 06.354 b = 2
19: 33: 07.615 c = 3
19: 33: 09.981 arr = [a, b, c]
19: 33: 16.460 arr1 = arr

19: 33: 20.317 arr1 === arr
19: 33: 20.331 จริง

19: 33: 43.592 arr.removeContained ([a, c])
19: 33: 52.433 arr === arr1
19: 33: 52.438จริง

การใช้ Angular framework เป็นวิธีที่ดีที่สุดในการรักษาตัวชี้ไปยังวัตถุต้นฉบับเมื่อคุณอัปเดตคอลเลกชันโดยไม่ต้องมีผู้เฝ้าดูและโหลดซ้ำจำนวนมาก


คำตอบนี้ไม่ดีเนื่องจากเป็นช่องว่างในการปฏิบัติที่ดีที่สุด ห้ามดัดแปลงวัตถุที่คุณไม่ได้เป็นเจ้าของ ในกรณีนี้คุณกำลังแก้ไขวัตถุ Array ซึ่งไม่มีขนาดใหญ่
Hybrid web dev

0

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

var myArray = [
            {name: 'deepak', place: 'bangalore'},
            {name: 'alok', place: 'berhampur'},
            {name: 'chirag', place: 'bangalore'},
            {name: 'chandan', place: 'mumbai'},

        ];
        var toRemove = [

            {name: 'chirag', place: 'bangalore'},
            {name: 'deepak', place: 'bangalore'},
            /*{name: 'chandan', place: 'mumbai'},*/
            /*{name: 'alok', place: 'berhampur'},*/


        ];
        var tempArr = [];
        for( var i=0 ; i < myArray.length; i++){
            for( var j=0; j<toRemove.length; j++){
                var toRemoveObj = toRemove[j];
                if(myArray[i] && (myArray[i].name === toRemove[j].name)) {
                    break;
                }else if(myArray[i] && (myArray[i].name !== toRemove[j].name)){
                        var fnd = isExists(tempArr,myArray[i]);
                        if(!fnd){
                            var idx = getIdex(toRemove,myArray[i])
                            if (idx === -1){
                                tempArr.push(myArray[i]);
                            }

                        }

                    }

                }
        }
        function isExists(source,item){
            var isFound = false;
            for( var i=0 ; i < source.length; i++){
                var obj = source[i];
                if(item && obj && obj.name === item.name){
                    isFound = true;
                    break;
                }
            }
            return isFound;
        }
        function getIdex(toRemove,item){
            var idex = -1;
            for( var i=0 ; i < toRemove.length; i++){
                var rObj =toRemove[i];
                if(rObj && item && rObj.name === item.name){
                    idex=i;
                    break;
                }
            }
            return idex;
        }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.