Javascript ES6 / ES5 dizide bul ve değiştir


133

Bir dizi nesnem var. Bir alana göre bulmak ve sonra değiştirmek istiyorum:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

var foundItem = items.find(x => x.id == item.id);
foundItem = item;

Orijinal nesneyi değiştirmesini istiyorum. Nasıl? (Lodash'ta olup olmayacağı da umurumda değil)


Yeni nesneniz itembir idanahtar içeriyor mu? veya itemdizi girişinde nesnenin tüm özelliklerinin yanı sıra id'nin de olmasını ister misiniz ?
Koushik Chatterjee

Yanıtlar:


252

Dizini nesne dizisinde bulmak ve gerektiği gibi değiştirmek için findIndex'i kullanabilirsiniz :

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

var foundIndex = items.findIndex(x => x.id == item.id);
items[foundIndex] = item;

Bu, benzersiz kimlikler olduğunu varsayar. Kimlikleriniz yineleniyorsa (örneğinizde olduğu gibi), muhtemelen forEach'i kullanmanız daha iyidir:

items.forEach((element, index) => {
    if(element.id === item.id) {
        items[index] = item;
    }
});

16
@georg Bu yine de yeni bir dizi döndürecektir.
CodingIntrigue

3
=> İşlevi IE11'de çalışmaz. Son zamanlarda bununla ısırıldı.
Lewis Cianci

1
letyerine anahtar kelime kullanmak daha iyi olabilirvar
Inus Saha

Bilginize, bu phantomJS'nin bazı sürümlerinde çalışmıyor
Sid

1
@Georg'un kullandığı tek satırlık yöntemi kullanmak yerine @CodingIntrigue'nun kullandığı daha ayrıntılı yöntemi tercih ediyorum map. Neler olduğunu anlamak için daha az zihinsel jimnastik gerekli. Ekstra kod satırına değer.
Joshua Pinter

44

En iyi yaklaşımım:

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

items[items.findIndex(el => el.id === item.id)] = item;

FindIndex için referans

Yeni nesneyle değiştirmek istemiyorsanız, bunun yerine alanlarını kopyalamak itemistiyorsanız, şunu kullanabilirsiniz Object.assign:

Object.assign(items[items.findIndex(el => el.id === item.id)], item)

şununla alternatif olarak .map():

Object.assign(items, items.map(el => el.id === item.id? item : el))

Fonksiyonel yaklaşım :

Diziyi değiştirmeyin, yeni bir tane kullanın, böylece yan etkiler oluşturmazsınız

const updatedItems = items.map(el => el.id === item.id ? item : el)

1
Asıl soru İngilizce ise lütfen İngilizce bir sayfaya bağlantı verin. Ayrıca, bu örnek nesnenin her zaman bulunduğunu varsayar.
2017

1
Her zaman bir deneme yakalama ifadesine sarabilirsiniz o zaman ... değil mi?
Soldeplata Saketos

1
Ve gönderilerin sorusuna tamamen gerçek olduğundan, bir dizideki bir öğeyi düzenlemek istiyor. Var olup olmadığını bilmek istemiyor, bu yüzden bunu daha önce yaptığını varsayıyoruz.
Soldeplata Saketos

Evet @SoldeplataSaketos, sen verebilir bir alanına kaydırmak try/catchelemanı görmediklerine istisnai bir durum değildir çünkü, ama sen olmamalı; bu, dönüş değerini kontrol ederek findIndexve ardından yalnızca öğe bulunduğunda diziyi güncelleyerek hesaba katmanız gereken standart bir durumdur .
Wayne

20

Diğer bir yaklaşım, splice kullanmaktır .

splice()Yöntem, çıkarma veya varolan öğeleri değiştirerek ve / veya yeni elemanları eklenerek bir dizi içeriğini değiştirir yerine .

Not: Reaktif çerçevelerle çalışıyorsanız, "görünümü", yani onu güncellediğinizi "bilerek" dizinizi güncelleyecektir.

Cevap :

var item = {...}
var items = [{id:2}, {id:2}, {id:2}];

let foundIndex = items.findIndex(element => element.id === item.id)
items.splice(foundIndex, 1, item)

Ve bir öğenin yalnızca bir değerini değiştirmek istiyorsanız, bul işlevini kullanabilirsiniz :

// Retrieve item and assign ref to updatedItem
let updatedItem = items.find((element) => { return element.id === item.id })

// Modify object property
updatedItem.aProp = ds.aProp

15

Değişen bir nesne ve bir dizi verildiğinde:

const item = {...}
let items = [{id:2}, {id:3}, {id:4}];

Dizi üzerinde yineleyerek diziyi yeni nesneyle güncelleyin:

items = items.map(x => (x.id === item.id) ? item : x)

Lütfen kodu yapıştırmayın. Ne yapıldığını ve bunun sorunu nasıl çözdüğünü açıklayın.
Spencer

1
Bunun en iyi çözüm olduğunu düşünüyorum çünkü diziyi yalnızca bir kez gözden geçiriyor ve dizinin referansını değiştiriyor, böylece değişken durumlardan kaçınacak
Ohad Sadan

6

Kullanım olabilir Filtre .

const list = [{id:0}, {id:1}, {id:2}];
let listCopy = [...list];
let filteredDataSource = listCopy.filter((item) => {
       if (item.id === 1) {
           item.id = 12345;
        }

        return item;
    });
console.log(filteredDataSource);

Dizi [Nesne {id: 0}, Nesne {id: 12345}, Nesne {id: 2}]


Filtreyi seviyorum çünkü yeni bir dizi oluşturmaya izin veriyor ve bunun için de mevcut olmayan girişler 'siliniyor'
pungggi

0

benim için çalıştı

let returnPayments = [ ...this.payments ];

returnPayments[this.payments.findIndex(x => x.id == this.payment.id)] = this.payment;

1
Lütfen kodu yapıştırmayın. Ne yapıldığını ve bunun sorunu nasıl çözdüğünü açıklayın.
Adrian Mole

Kabul edilen en çok oylanan cevap pek farklı değil, ancak cevaplarını orada güncelleyerek onlara işaret etmediniz .. Neden bu?
li x

0

Mevcut yanıtların çoğu harika olsa da, burada da dikkate alınması gereken geleneksel bir for döngüsü kullanan bir yanıt eklemek istiyorum. OP, ES5 / ES6 uyumlu bir yanıt ister ve geleneksel for döngüsü geçerlidir :)

Bu senaryoda dizi işlevlerini kullanmanın sorunu, nesneleri değiştirmemeleridir, ancak bu durumda mutasyon bir gerekliliktir. Geleneksel bir for döngüsü kullanmanın performans kazancı sadece (çok büyük) bir bonus.

const findThis = 2;
const items = [{id:1, ...}, {id:2, ...}, {id:3, ...}];

for (let i = 0, l = items.length; i < l; ++i) {
  if (items[i].id === findThis) {
    items[i].iAmChanged = true;
    break;
  }
}

Dizi işlevlerinin büyük bir hayranı olsam da, bunların alet kutunuzdaki tek araç olmasına izin vermeyin. Amaç diziyi değiştirmekse, bunlar en uygun olanlar değildir.


0

Yayılma operatörünü kullanan tek astar.

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
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.