Xóa tất cả các thành phần có trong một mảng khác


222

Tôi đang tìm kiếm một cách hiệu quả để loại bỏ tất cả các yếu tố khỏi một mảng javascript nếu chúng có mặt trong một mảng khác.

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

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

Tôi muốn hoạt động trên myArray để nó ở trạng thái này: ['a', 'd', 'e', 'f']

Với jQuery, tôi đang sử dụng grep()inArray()hoạt động tốt:

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

Có một cách javascript thuần túy để làm điều này mà không cần lặp và nối?



4
có thể trùng lặp về chênh lệch mảng JavaScript
Thuốc nổ

1
có thể trùng lặp Bạn có thể xóa một mảng từ một mảng khác trong javascript hoặc jquery - bạn không thể chú ý nhiều đến các đề xuất được đưa ra khi bạn viết câu hỏi
mplungjan

Dù thế nào đi chăng nữa, nó sẽ luôn liên quan đến việc lặp ở một mức độ nào đó.
Bầu trời xanh

Nếu bạn thực sự muốn nó "hiệu quả", bạn sẽ không sử dụng các phương thức loại chức năng như .filter(). Thay vào đó, bạn sẽ sử dụng forcác vòng lặp. Bạn có thể tránh .splice()nếu đơn hàng ban đầu không cần phải duy trì. Hoặc có nhiều cách để làm cho .splice()hiệu quả hơn nếu bạn nghĩ rằng sẽ có nhiều mục để loại bỏ.
Bầu trời xanh

Câu trả lời:


379

Sử dụng Array.filter()phương pháp:

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

Cải thiện nhỏ, khi hỗ trợ trình duyệt Array.includes()đã tăng:

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

Thích ứng tiếp theo bằng cách sử dụng các chức năng mũi tên :

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

23
OP: Nếu bạn đang sử dụng Underscore.js thì .difference()về cơ bản là có.
Bill Criswell

Chỉ cần những gì tôi đang tìm kiếm. Cảm ơn bạn. @BillCriswell, tôi sẽ kiểm tra gạch dưới.
Nhấn vào

1
@AlecRust Chuyển đổi tất cả các thành phần của toRemove()chữ hoa và thay đổi trong cuộc gọi lại từ elsang el.toUpperCase().
Sirko

5
hoặc ngắn hơn:myArray = myArray.filter( el => !toRemove.includes( el ) );
538ROMEO

1
không phải thứ tự này n ^ 2 sao?
Frazer Kirkman

34

Các filterphương pháp nên làm các trick:

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

Nếu toRemovemảng của bạn lớn, kiểu mẫu tra cứu này có thể không hiệu quả. Nó sẽ được thực hiện nhiều hơn để tạo ra một bản đồ để tìm kiếm O(1)hơn là 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

Nếu bạn đang sử dụng một mảng các đối tượng. Sau đó, mã dưới đây sẽ làm điều kỳ diệu, trong đó một thuộc tính đối tượng sẽ là tiêu chí để loại bỏ các mục trùng lặp.

Trong ví dụ dưới đây, các bản sao đã bị xóa so sánh tên của từng mục.

Hãy thử ví dụ này. 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

Bộ ECMAScript 6 có thể được sử dụng để tính toán các yếu tố khác nhau của hai mảng:

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

Tôi chỉ thực hiện như:

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

Sử dụng như là:

myArray.exclude(toRemove);

1
Nó không phải là thực hành tốt để mở rộng prototypescác Đối tượng bản địa, như vậy Array. Điều đó có thể có mâu thuẫn lâu dài với sự phát triển ngôn ngữ trong tương lai ( xem flattentrường hợp )
MarcoL

6

Nếu bạn không thể sử dụng công cụ ES5 mới, filtertôi nghĩ bạn bị mắc kẹt với hai vòng:

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

bộ lọc không phải là "công cụ HTML5 mới"
goofballLogic

Tôi nên đã viết "ES5 thứ". Nó không khả dụng với 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) ))

Bạn có phiền khi thêm một số lời giải thích cho một câu hỏi được đón nhận như vậy không?
hòa

1
Tôi đã tìm kiếm hàng giờ để tìm giải pháp cho vấn đề và chỉ tìm thấy nó, thật tuyệt vời. Cảm ơn rât nhiều!
Tarvo Mäesepp

5

Bây giờ trong hương vị một lớp lót:

console.log(['a', 'b', 'c', 'd', 'e', 'f', 'g'].filter(x => !~['b', 'c', 'g'].indexOf(x)))

Có thể không hoạt động trên các trình duyệt cũ.


3

Bạn có thể sử dụng _.differenceBy từ 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');

Mã ví dụ ở đây: CodePen


Nếu thuộc tính được lồng bên trong đối tượng thì sao? Một cái gì đó thử nghiệm như trong trường hợp của bạn {name: 'deepak', place: 'bangalore', lồng nhau: {test: 1}}
Charith Jayasanka

2

Làm thế nào về đơn giản nhất có thể:

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
Hãy nhớ rằng includeskhông có sẵn trước ES7.
Greg

0

Cách thích hợp để loại bỏ tất cả các phần tử có trong một mảng khác là tạo cho mảng nguồn cùng một đối tượng bằng cách chỉ xóa các phần tử:

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

Hoặc tương đương với CoffeeScript:

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

Kiểm tra bên trong các công cụ phát triển chrome:

19: 33: 04.447 a = 1
19: 33: 06.354 b = 2
19: 33: 07.615 c = 3
19: 33: 09.981 mảng = [a, b, c]
19: 33:

19: 33: 20.317 mảng1 === mảng
19: 33: 20.331 đúng

19: 33: 43.592 mảng.removeContained ([a, c])
19: 33: 52.433 mảng === mảng1
19: 33: 52.438 đúng

Sử dụng khung Angular là cách tốt nhất để giữ con trỏ tới đối tượng nguồn khi bạn cập nhật các bộ sưu tập mà không cần số lượng lớn người theo dõi và tải lại.


Câu trả lời này là xấu vì nó nói lên những thực tiễn tốt nhất. Cụ thể, không bao giờ sửa đổi các đối tượng bạn không sở hữu. Trong trường hợp này, bạn đang sửa đổi đối tượng Array, đây là một điều không nên.
Lai web dev

0

Tôi xây dựng logic mà không sử dụng bất kỳ phương thức tích hợp nào, vui lòng cho tôi biết bất kỳ tối ưu hóa hoặc sửa đổi nào. Tôi đã thử nghiệm trong trình soạn thảo JS, nó hoạt động tốt.

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