nesneleri nesne tarafından diziden kaldır


138
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

Nesne özelliğini eşleştirerek diziden bir nesneyi nasıl kaldırabilirim?

Sadece yerel JavaScript lütfen.

Eklemeyi kullanırken sorun yaşıyorum çünkü uzunluk her silme işleminde azalıyor. Orignal indeks üzerinde klonlama ve birleştirme kullanma, hala azalan uzunluk problemi ile sonuçlanır.


1
Geriye doğru döngü, uzunluk problemindeki değişikliği düzeltmelidir
Ian

1
Öyle bir utanç ki, bir nesne dizisinden öğeleri kaldırmak için standart uygun bir yol yoktur. Çok fazla 3. parti senaryosu olduğuna şaşmamalı. Bu temel bir şey.
guitarlass

Yanıtlar:


155

Sanırım spliceböyle bir şey kullandın mı?

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

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

Hatayı düzeltmek için yapmanız gereken tek şey i, bir dahaki sefere azalmaktır , ve (geri döngü de bir seçenektir):

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

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

Doğrusal zaman silmelerini önlemek için , dizinin üzerinde tutmak istediğiniz dizi öğelerini yazabilirsiniz :

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;

ve modern bir çalışma zamanında doğrusal zaman aramasını önlemek için bir karma kümesini kullanabilirsiniz:

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;

güzel bir işlevle sarılabilir:

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

Yerinde yapmanız gerekmiyorsa, bu Array#filter:

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

80

Aşağıdaki gibi herhangi bir üçüncü taraf kütüphanesi kullanmadan bir öğeyi özelliklerinden biriyle kaldırabilirsiniz:

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

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

1
Bu gerçekten zarif bir cevap.
Scott Silvi

istediğim başka bir şey, dizideki her nesne için ayrı düğmeler olacak. Ben dizi düğme tıklatıldığında belirli bir nesneyi silmek istiyorsanız ve bu başka bir ikincil diziye taşımak gerekir. nasıl yapılır . öğeleri oluşturmak için açısal js ng-tekrar kullandık. bana yardım edebilir misin
Thilak Raj

çok güzel ve zarif bir yaklaşım. şeref! Dikkat edilmesi gereken tek bir şey var; harita dizisinde gerekli dizin bulunamazsa -1 döndürür; böylece ekleme son elemanı kaldırır.
mcy

15
Veya son satırdaki tilde kafanız karışırsa, bunu daha net bulabilirsiniz: (removeIndex> = 0) && array.splice (removeIndex, 1);
wojjas

1
@parliament - Örneğinizde dalga işaretiyle ilgili herhangi bir belge var mı? Bunu daha önce hiç görmedim.
webdad3

43

Lodash / alt çizgi ile:

Varolan dizinin kendisini değiştirmek istiyorsanız, splice kullanmamız gerekir . FindWhere alt çizgi / lodash kullanarak biraz daha iyi / okunabilir yolu :

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

ES5 veya üstü ile

( lodash / alt çizgi olmadan )

ES5'ten sonra findIndexdizi üzerinde yöntemimiz var , bu yüzden lodash / alt çizgi olmadan kolay

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

(ES5 neredeyse tüm morden tarayıcılarda desteklenir)

FindIndex ve Tarayıcı uyumluluğu hakkında


nasıl nesne dizisindeki tüm öğeleri kaldırmak ama ben de geri arama gerekir
Muhaimin

geri arama ile ne demek istiyorsun, yukarıdaki kodu nesneyi diziden kaldırmak için kullanabilirsiniz ..
Rahul R.

1
Güzel bir. Bunu alet kemerine ekleyeceğim
abyrne85

istediğim başka bir şey, dizideki her nesne için ayrı düğmeler olacak. Ben dizi düğme tıklatıldığında belirli bir nesneyi silmek istiyorsanız ve bu başka bir ikincil diziye taşımak gerekir. nasıl yapılır . öğeleri oluşturmak için açısal js ng-tekrar kullandık. bana yardım edebilir misin
Thilak Raj

1
Daha kısa bir şekilde bile yazılabildiği için bu ES5 önerisini seviyorumitems.splice(items.findIndex(i => i.id === "abc"), 1)
bramchi

27

findIndex modern tarayıcılar için çalışır:

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

Bu modern yanıtı beğendim, ancak kodunuz endeks = -1
rmcsharry

2
diğerlerine göre çok basit bir cevap ve gayet iyi çalışıyor.
arun

basit ama güçlü asnwer
Shelly

15

Bir nesneyi verilen dizideki kimliğiyle silmek için;

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

10

Sadece mevcut diziden kaldırmak ve yeni bir dizi oluşturmak istemiyorsanız, şunu deneyin:

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

7
bu cevabın alt çizgi kütüphanesini gerektirdiğine dikkat edin
JoshuaDavid

2
Öğeyi bulamazsanız, _.indexOf -1 => items.splice (-1,1)
user1441287

6

iSorunu önlemek için azaltarak ters çevirin :

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

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

Veya şunu kullanın filter:

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


4

Sadece yerel JavaScript lütfen.

ECMAScript 5 üzerinde çalışan alternatif, daha "işlevsel" bir çözüm olarak şunları kullanabilirsiniz:

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' } ]

ECMA-262'deki 'Array.prototype.reduceRight' tanımına göre :

reduceRight, çağrıldığı nesneyi doğrudan değiştirmez, ancak nesne callbackfn çağrılarıyla mutasyona uğrayabilir .

Yani bu geçerli bir kullanımdır reduceRight.


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

cevabınıza göre böyle olacak. Belirli bir nesneyi tıklattığınızda, beni sil işlevi için parametrede dizini gönderin. Bu basit kod cazibe gibi çalışacaktır.

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

1
Thnaks bu çok yardımcı oldu :)
RAJESH KUMAR ARUMUGAM

1

filtre ve index ile

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

filtre ve içerir

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

0

Kısa ve kendini tanımlayan parametreleri seviyorsanız veya splicedüz bir filtreyle kullanmak ve gitmek istemiyorsanız veya sadece benim gibi bir SQL kişisiyseniz:

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

Ve örnek bir kullanım:

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

Kullanabilirsiniz filter. Koşul doğruysa bu yöntem her zaman öğeyi döndürür. Bu nedenle, kimliğe göre kaldırmak istiyorsanız, verilen kimliğe uymayan tüm öğeleri saklamanız gerekir. İşte bir örnek:

arrayOfObjects = arrayOfObjects.filter (obj => obj.id! = idToRemove)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.