loại bỏ các đối tượng khỏi mảng bởi thuộc tính đối tượng


136
var listToDelete = ['abc', 'efg'];

var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

Làm cách nào để xóa một đối tượng khỏi mảng bằng cách khớp thuộc tính đối tượng?

Chỉ có JavaScript bản địa.

Tôi gặp sự cố khi sử dụng mối nối vì chiều dài giảm dần sau mỗi lần xóa. Sử dụng bản sao và nối trên chỉ số gốc vẫn khiến bạn gặp vấn đề về độ dài giảm dần.


1
Vòng lặp ngược sẽ khắc phục sự thay đổi trong vấn đề độ dài
Ian

1
Thật xấu hổ khi không có một cách thích hợp tiêu chuẩn để loại bỏ các mục khỏi một mảng đối tượng. Không có gì ngạc nhiên khi có rất nhiều kịch bản của bên thứ 3. Đó là một điều cơ bản.
guitarlass

Câu trả lời:


155

Tôi giả sử bạn đã sử dụng splicemột cái gì đó như thế này?

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
    }
}

Tất cả những gì bạn cần làm để khắc phục lỗi là giảm dần icho lần tiếp theo, sau đó (và lặp lại cũng là một tùy chọn):

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
        i--;
    }
}

Để tránh xóa thời gian tuyến tính, bạn có thể viết các phần tử mảng mà bạn muốn theo dõi mảng:

var end = 0;

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) === -1) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

và để tránh tra cứu thời gian tuyến tính trong thời gian chạy hiện đại, bạn có thể sử dụng bộ băm:

const setToDelete = new Set(listToDelete);
let end = 0;

for (let i = 0; i < arrayOfObjects.length; i++) {
    const obj = arrayOfObjects[i];

    if (setToDelete.has(obj.id)) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

có thể được gói trong một chức năng tốt đẹp:

const filterInPlace = (array, predicate) => {
    let end = 0;

    for (let i = 0; i < array.length; i++) {
        const obj = array[i];

        if (predicate(obj)) {
            array[end++] = obj;
        }
    }

    array.length = end;
};

const toDelete = new Set(['abc', 'efg']);

const arrayOfObjects = [{id: 'abc', name: 'oh'},
                        {id: 'efg', name: 'em'},
                        {id: 'hij', name: 'ge'}];

filterInPlace(arrayOfObjects, obj => !toDelete.has(obj.id));
console.log(arrayOfObjects);

Nếu bạn không cần phải làm điều đó tại chỗ, đó là Array#filter:

const toDelete = new Set(['abc', 'efg']);
const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));

79

Bạn có thể xóa một mục bằng một trong các thuộc tính của nó mà không cần sử dụng bất kỳ libs bên thứ 3 nào như thế này:

var removeIndex = array.map(item => item.id)
                       .indexOf("abc");

~removeIndex && array.splice(removeIndex, 1);

1
Đây là một câu trả lời thực sự thanh lịch.
Scott Silvi

Một điều tôi muốn, Sẽ có các nút riêng biệt cho mọi đối tượng trong mảng. nếu tôi muốn xóa đối tượng cụ thể đó trong nút mảng đã nhấp và nên chuyển sang mảng thứ cấp khác. làm thế nào để làm nó . tôi đã sử dụng js ng-repeat góc để tạo ra các mục. bạn có thể giúp tôi không
Thilak Raj

cách tiếp cận rất đẹp và thanh lịch. thanh danh! Chỉ cần một điều cần thận trọng; nếu không tìm thấy chỉ mục yêu cầu trên mảng bản đồ, nó sẽ trả về -1; do đó mối nối sẽ loại bỏ phần tử cuối cùng.
MCY

14
Hoặc nếu bạn bị nhầm lẫn bởi dấu ngã trên dòng cuối cùng, bạn có thể thấy điều này rõ ràng hơn: (remove Index> = 0) && mảng.splice (remove Index, 1);
wojjas

1
@parferences - Có tài liệu nào về dấu ngã trong ví dụ của bạn không? Tôi chưa bao giờ thấy điều này trước đây.
webdad3

43

Với lodash / gạch dưới:

Nếu bạn muốn tự sửa đổi mảng hiện có, thì chúng ta phải sử dụng mối nối . Dưới đây là cách tốt hơn / dễ đọc hơn bằng cách sử dụng findWhere of undererscore / lodash:

var items= [{id:'abc',name:'oh'}, // delete me
                  {id:'efg',name:'em'},
                  {id:'hij',name:'ge'}];

items.splice(_.indexOf(items, _.findWhere(items, { id : "abc"})), 1);

Với ES5 trở lên

( không có lodash / gạch dưới )

Với ES5 trở đi, chúng ta có findIndexphương thức trên mảng, vì vậy thật dễ dàng mà không cần lodash / gạch dưới

items.splice(items.findIndex(function(i){
    return i.id === "abc";
}), 1);

(ES5 được hỗ trợ trong hầu hết các trình duyệt hiện đại)

Giới thiệu về find Index khả năng tương thích Trình duyệt của nó


Làm cách nào để xóa tất cả các mục trong mảng đối tượng nhưng tôi cũng cần gọi lại
Muhaimin

Bạn có ý nghĩa gì khi gọi lại, bạn có thể sử dụng đoạn mã trên để xóa đối tượng khỏi mảng ..
Rahul R.

1
Đẹp một. Tôi sẽ thêm phần này vào toolbelt của mình
abyrne85

Một điều tôi muốn, Sẽ có các nút riêng biệt cho mọi đối tượng trong mảng. nếu tôi muốn xóa đối tượng cụ thể đó trong nút mảng đã nhấp và nên chuyển sang mảng thứ cấp khác. làm thế nào để làm nó . tôi đã sử dụng js ng-repeat góc để tạo ra các mục. bạn có thể giúp tôi không
Thilak Raj

1
Thích đề xuất ES5 này, vì nó thậm chí có thể được viết theo cách ngắn hơnitems.splice(items.findIndex(i => i.id === "abc"), 1)
bramchi

27

find Index hoạt động cho các trình duyệt hiện đại:

var myArr = [{id:'a'},{id:'myid'},{id:'c'}];
var index = arr.findIndex(function(o){
     return o.id === 'myid';
})
if (index !== -1) myArr.splice(index, 1);

Tôi thích câu trả lời hiện đại này, ngoại trừ mã của bạn không bắt được trường hợp khi index = -1
rmcsharry

2
câu trả lời rất đơn giản so với những người khác và chỉ hoạt động tốt.
arun

đơn giản nhưng mạnh mẽ asnwer
Shelly

15

Để xóa một đối tượng bởi id của nó trong mảng đã cho;

const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
//remove hero1
const updatedHero = hero.filter(item => item.id !== 1);

10

Nếu bạn chỉ muốn xóa nó khỏi mảng hiện có và không tạo một mảng mới, hãy thử:

var items = [{Id: 1},{Id: 2},{Id: 3}];
items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);

7
lưu ý rằng câu trả lời này yêu cầu thư viện gạch dưới
JoshuaDavid

2
Tôi sẽ không đề xuất điều này bởi vì nếu không tìm thấy phần tử _.indexOf sẽ trả về -1 => items.splice (-1,1)
user1441287

6

Lặp lại theo chiều ngược lại bằng cách giảm iđể tránh vấn đề:

for (var i = arrayOfObjects.length - 1; i >= 0; i--) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
    }
}

Hoặc sử dụng filter:

var newArray = arrayOfObjects.filter(function(obj) {
    return listToDelete.indexOf(obj.id) === -1;
});


4

Chỉ có JavaScript bản địa.

Là một giải pháp thay thế, "chức năng" hơn, hoạt động trên ECMAScript 5, bạn có thể sử dụng:

var listToDelete = ['abc', 'efg'];
var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}]; // all that should remain

arrayOfObjects.reduceRight(function(acc, obj, idx) {
    if (listToDelete.indexOf(obj.id) > -1)
        arrayOfObjects.splice(idx,1);
}, 0); // initial value set to avoid issues with the first item and
       // when the array is empty.

console.log(arrayOfObjects);
[ { id: 'hij', name: 'ge' } ]

Theo định nghĩa của 'Array.prototype.reduceRight' trong ECMA-262 :

lessRight không trực tiếp làm biến đổi đối tượng mà nó được gọi nhưng đối tượng có thể bị đột biến bởi các lệnh gọi tới callbackfn .

Vì vậy, đây là một cách sử dụng hợp lệ reduceRight.


2
var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

theo câu trả lời của bạn sẽ như thế này khi bạn bấm vào một số đối tượng cụ thể, gửi chỉ mục trong param cho hàm xóa tôi. Mã đơn giản này sẽ làm việc như quyến rũ.

function deleteme(i){
    if (i > -1) {
      arrayOfObjects.splice(i, 1);
    }
}

1
Điều này đã giúp rất nhiều :)
RAJESH KUMAR ARUMUGAM

1

với bộ lọc & indexOf

withLodash = _.filter(arrayOfObjects, (obj) => (listToDelete.indexOf(obj.id) === -1));
withoutLodash = arrayOfObjects.filter(obj => listToDelete.indexOf(obj.id) === -1);

với bộ lọc và bao gồm

withLodash = _.filter(arrayOfObjects, (obj) => (!listToDelete.includes(obj.id)))
withoutLodash = arrayOfObjects.filter(obj => !listToDelete.includes(obj.id));

0

Nếu bạn thích các tham số mô tả ngắn và tự mô tả hoặc nếu bạn không muốn sử dụng splicevà sử dụng bộ lọc chuyển tiếp thẳng hoặc nếu bạn chỉ đơn giản là một người SQL như tôi:

function removeFromArrayOfHash(p_array_of_hash, p_key, p_value_to_remove){
    return p_array_of_hash.filter((l_cur_row) => {return l_cur_row[p_key] != p_value_to_remove});
}

Và một cách sử dụng mẫu:

l_test_arr = 
[
    {
         post_id: 1,
        post_content: "Hey I am the first hash with id 1"
    },
    {
        post_id: 2,
        post_content: "This is item 2"
    },
    {
        post_id: 1,
        post_content: "And I am the second hash with id 1"
    },
    {
        post_id: 3,
        post_content: "This is item 3"
    },
 ];



 l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 2); // gives both of the post_id 1 hashes and the post_id 3
 l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 1); // gives only post_id 3 (since 1 was removed in previous line)

-1

Bạn có thể sử dụng filter. Phương thức này luôn trả về phần tử nếu điều kiện là đúng. Vì vậy, nếu bạn muốn xóa theo id, bạn phải giữ tất cả phần tử không khớp với id đã cho. Đây là một ví dụ:

mảngOfObjects = mảngOfObjects.filter (obj => obj.id! = idToRemove)

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.