Javascript ES6 / ES5 trouver dans le tableau et changer

133

J'ai un tableau d'objets. Je veux trouver par un champ, puis le changer:

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

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

Je veux qu'il change l'objet d'origine. Comment? (Je m'en fiche si ce sera aussi en lodash)

utilisateur3712353
la source
Dose votre nouvel objet itemcontient une idclé? ou cela vous dérange-t-il d'avoir l'id ainsi que toutes les propriétés de l' itemobjet dans l'entrée du tableau?
Koushik Chatterjee

Réponses:

252

Vous pouvez utiliser findIndex pour rechercher l'index dans le tableau de l'objet et le remplacer si nécessaire:

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

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

Cela suppose des identifiants uniques. Si vos identifiants sont dupliqués (comme dans votre exemple), il est probablement préférable d'utiliser forEach:

items.forEach((element, index) => {
    if(element.id === item.id) {
        items[index] = item;
    }
});
CodageIntrigue
la source
16
@georg Cela renverrait cependant un nouveau tableau.
CodingIntrigue
3
La fonction => ne fonctionnera pas dans IE11. Récemment mordu par ça.
Lewis Cianci
1
peut-être serait-il préférable d'utiliser un letmot-clé au lieu devar
Inus Saha
Juste pour info, cela ne fonctionne pas dans certaines versions de phantomJS
Sid
1
Je préfère la méthode plus verbeuse utilisée par @CodingIntrigue au lieu d'utiliser le one-liner maputilisé par @georg. Moins de gymnastique mentale nécessaire pour comprendre ce qui se passe. Vaut la ligne de code supplémentaire.
Joshua Pinter
44

Ma meilleure approche est:

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

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

Référence pour findIndex

Et au cas où vous ne voudriez pas remplacer par un nouvel objet, mais plutôt copier les champs de item, vous pouvez utiliser Object.assign:

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

comme alternative avec .map():

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

Approche fonctionnelle :

Ne modifiez pas le tableau, utilisez-en un nouveau pour ne pas générer d'effets secondaires

const updatedItems = items.map(el => el.id === item.id ? item : el)
Soldeplata Saketos
la source
1
Veuillez créer un lien vers une page en anglais si la question originale était en anglais. De plus, cet exemple suppose que l'objet est toujours trouvé.
raarts
1
Vous pouvez toujours l'envelopper dans une expression try catch alors ... non?
Soldeplata Saketos
1
Et étant complètement littéral à la question des articles, il veut éditer un élément dans un tableau. Il ne veut pas savoir s'il existe ou non, alors nous supposons qu'il l'a déjà fait avant.
Soldeplata Saketos
@SoldeplataSaketos oui, vous pouvez l' envelopper dans un try/catch, mais vous ne devriez pas, car ne pas trouver l'élément n'est pas un cas exceptionnel; c'est un cas standard que vous devez prendre en compte en vérifiant la valeur de retour de findIndex, puis en ne mettant à jour le tableau que lorsque l'élément a été trouvé.
Wayne le
20

Une autre approche consiste à utiliser l' épissure .

La splice()méthode modifie le contenu d'un tableau en supprimant ou en remplaçant des éléments existants et / ou en ajoutant de nouveaux éléments en place .

NB: Si vous travaillez avec des frameworks réactifs, il mettra à jour la "vue", votre tableau "sachant" que vous l'avez mis à jour.

Répondre :

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

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

Et si vous souhaitez uniquement modifier la valeur d'un élément, vous pouvez utiliser la fonction de recherche :

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

// Modify object property
updatedItem.aProp = ds.aProp
Toodoo
la source
14

Étant donné un objet modifié et un tableau:

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

Mettez à jour le tableau avec le nouvel objet en itérant sur le tableau:

items = items.map(x => (x.id === item.id) ? item : x)
Compagnon étranger
la source
Veuillez ne pas simplement coller du code. Expliquez ce qui est fait et comment cela résout le problème.
Spencer
1
Je pense que c'est la meilleure solution car elle a les meilleures performances car elle ne parcourt le tableau qu'une seule fois et change également la référence du tableau, donc cela évitera les situations mutables
Ohad Sadan
6

Peut être utiliser Filter .

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 [Objet {id: 0}, Objet {id: 12345}, Objet {id: 2}]

Katwal-Dipak
la source
J'aime le filtre car il permet de créer un nouveau tableau et pour cela, les entrées non existantes sont `` supprimées ''
pungggi
0

travaillé pour moi

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

returnPayments[this.payments.findIndex(x => x.id == this.payment.id)] = this.payment;
Daniel Laera
la source
1
Veuillez ne pas simplement coller du code. Expliquez ce qui est fait et comment cela résout le problème.
Adrian Mole
La réponse acceptée la plus votée n'est pas très différente, mais vous ne leur avez pas indiqué de mettre à jour leur réponse ... pourquoi?
li x
0

Alors que la plupart des réponses existantes sont excellentes, j'aimerais inclure une réponse utilisant une boucle for traditionnelle, qui devrait également être considérée ici. L'OP demande une réponse compatible ES5 / ES6, et la boucle for traditionnelle s'applique :)

Le problème avec l'utilisation des fonctions de tableau dans ce scénario, est qu'elles ne mutent pas les objets, mais dans ce cas, la mutation est une exigence. Le gain de performance lié à l'utilisation d'une boucle for traditionnelle n'est qu'un (énorme) 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;
  }
}

Bien que je sois un grand fan des fonctions de tableau, ne les laissez pas être le seul outil de votre boîte à outils. Si le but est de faire muter le tableau, ils ne sont pas la meilleure solution.

Jørgen
la source
0

Monotouche utilisant un opérateur d'épandage.

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
tonymayoral
la source