Javascript ES6 / ES5 trova in array e cambia


133

Ho una serie di oggetti. Voglio trovare un campo e poi cambiarlo:

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

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

Voglio che cambi l'oggetto originale. Come? (Non mi importa se sarà anche in lodash)


Dose il tuo nuovo oggetto itemcontiene una idchiave? o ti dispiace avere l'id e tutte le proprietà itemdell'oggetto nella voce dell'array?
Koushik Chatterjee,

Risposte:


251

È possibile utilizzare findIndex per trovare l'indice nella matrice dell'oggetto e sostituirlo come richiesto:

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

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

Ciò presuppone ID univoci. Se i tuoi ID sono duplicati (come nel tuo esempio), probabilmente è meglio se usi per ogni:

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

16
@georg Questo restituirebbe un nuovo array.
CodingIntrigue

3
La funzione => non funzionerà in IE11. Di recente morso da questo.
Lewis Cianci,

1
potrebbe essere meglio usare la letparola chiave invece divar
Inus Saha il

Cordiali saluti, questo non funziona in alcune versioni di phantomJS
Sid

1
Preferisco il metodo più dettagliato che @CodingIntrigue usa invece di usare il one-liner mapche usa @georg. Meno ginnastica mentale necessaria per capire cosa sta succedendo. Vale la riga di codice aggiuntiva.
Joshua Pinter,

44

Il mio approccio migliore è:

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

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

Riferimento per findIndex

E nel caso in cui non si desideri sostituire con un nuovo oggetto, ma invece di copiare i campi di item, è possibile utilizzare Object.assign:

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

in alternativa con .map():

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

Approccio funzionale :

Non modificare l'array, utilizzane uno nuovo, in modo da non generare effetti collaterali

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

1
Si prega di collegarsi a una pagina inglese se la domanda originale era in inglese. Inoltre, questo esempio presuppone che l'oggetto sia sempre trovato.
Raar

1
Puoi sempre avvolgerlo in un'espressione catch try quindi ... giusto?
Soldeplata Saketos,

1
Ed essendo completamente letterale alla domanda dei post, vuole modificare un elemento in un array. Non vuole sapere se esiste o no, quindi supponiamo che lo abbia già fatto prima.
Soldeplata Saketos,

@SoldeplataSaketos sì, si poteva avvolgerlo in un try/catch, ma non si dovrebbe, perché non trovare l'elemento non è un caso eccezionale; è un caso standard da tenere in considerazione controllando il valore restituito findIndexe quindi aggiornando l'array solo quando l'elemento è stato trovato.
Wayne,

20

Un altro approccio è utilizzare la giunzione .

Il splice()metodo modifica il contenuto di un array rimuovendo o sostituendo elementi esistenti e / o aggiungendo nuovi elementi in atto .

NB: Nel caso in cui lavori con framework reattivi, aggiornerà la "vista", il tuo array "saprà" che lo hai aggiornato.

Risposta :

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

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

E nel caso in cui desideri modificare solo un valore di un articolo, puoi utilizzare la funzione find :

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

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

14

Dato un oggetto modificato e un array:

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

Aggiorna l'array con il nuovo oggetto ripetendo l'array:

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

Per favore, non basta incollare il codice. Spiega cosa viene fatto e come questo risolve il problema.
Spencer,

1
Penso che questa sia la soluzione migliore poiché ha le migliori prestazioni poiché va oltre l'array una sola volta e cambia anche il riferimento dell'array, quindi eviterà situazioni mutabili
Ohad Sadan,

6

Può essere utilizzare il filtro .

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

Array [Oggetto {id: 0}, Oggetto {id: 12345}, Oggetto {id: 2}]


Mi piace il filtro perché permette di creare un nuovo array e per questo anche le voci inesistenti vengono "cancellate"
pungggi

0

ha funzionato per me

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

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

1
Per favore, non basta incollare il codice. Spiega cosa viene fatto e come questo risolve il problema.
Adrian Mole,

La risposta più votata accettata non è molto diversa, ma non hai indicato che si sta aggiornando lì. Perché?
li x

0

Considerando che la maggior parte delle risposte esistenti sono ottime, vorrei includere una risposta usando un ciclo for tradizionale, che dovrebbe essere considerato anche qui. L'OP richiede una risposta compatibile ES5 / ES6 e si applica il tradizionale ciclo per :)

Il problema con l'uso delle funzioni di matrice in questo scenario è che non mutano oggetti, ma in questo caso la mutazione è un requisito. Il guadagno in termini di prestazioni derivante dall'uso di un ciclo tradizionale for è solo un (enorme) 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;
  }
}

Anche se sono un grande fan delle funzioni di array, non lasciarli essere l'unico strumento nella tua casella degli strumenti. Se lo scopo è la mutazione dell'array, non sono la soluzione migliore.


0

One-liner utilizzando l'operatore di diffusione.

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.