Javascript ES6 / ES5 buscar en matriz y cambiar

133

Tengo una gran variedad de objetos. Quiero buscar por algún campo, y luego cambiarlo:

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

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

Quiero que cambie el objeto original. ¿Cómo? (No me importa si también estará en lodash)

usuario3712353
fuente
¿Su nuevo objeto itemcontiene una idclave? ¿O le importaría tener la identificación y todas las propiedades del itemobjeto en la entrada de la matriz?
Koushik Chatterjee

Respuestas:

251

Puede usar findIndex para buscar el índice en la matriz del objeto y reemplazarlo según sea necesario:

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

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

Esto supone identificaciones únicas. Si sus ID están duplicadas (como en su ejemplo), probablemente sea mejor si usa forEach:

items.forEach((element, index) => {
    if(element.id === item.id) {
        items[index] = item;
    }
});
CodificaciónIntriga
fuente
16
@georg Sin embargo, eso devolvería una nueva matriz.
CodingIntrigue
3
La función => no funcionará en IE11. Recientemente mordido por esto.
Lewis Cianci el
1
puede ser mejor usar letpalabras clave en lugar devar
Inus Saha
Solo para tu información, esto no funciona en algunas versiones de phantomJS
Sid
1
Prefiero el método más detallado que @CodingIntrigue usa en lugar de usar el one-liner mapque usa @georg. Se requiere menos gimnasia mental para descubrir qué está pasando. Vale la pena la línea extra de código.
Joshua Pinter
44

Mi mejor enfoque es:

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

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

Referencia para findIndex

Y en caso de que no desee reemplazar con un nuevo objeto, sino que copie los campos item, puede usar Object.assign:

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

como alternativa con .map() :

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

Enfoque funcional :

No modifique la matriz, use una nueva, para no generar efectos secundarios.

const updatedItems = items.map(el => el.id === item.id ? item : el)
Soldeplata Saketos
fuente
1
Enlace a una página en inglés si la pregunta original estaba en inglés. Además, este ejemplo supone que el objeto siempre se encuentra.
raarts
1
Siempre puedes envolverlo en una expresión try catch entonces ... ¿verdad?
Soldeplata Saketos
1
Y siendo completamente literal a la pregunta de las publicaciones, quiere editar un elemento en una matriz. No quiere saber si existe o no, por lo que suponemos que ya lo hizo antes.
Soldeplata Saketos
@SoldeplataSaketos sí, podría envolverlo en un try/catch, pero no debería, porque no encontrar el elemento no es un caso excepcional; es un caso estándar que debe tener en cuenta al verificar el valor de retorno de findIndexy luego solo actualizar la matriz cuando se encontró el elemento.
Wayne
20

Otro enfoque es usar el empalme .

El splice()método cambia el contenido de una matriz eliminando o reemplazando elementos existentes y / o agregando nuevos elementos en su lugar .

NB: en caso de que esté trabajando con marcos reactivos, actualizará la "vista", su matriz "sabrá" que la ha actualizado.

Responder :

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

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

Y en caso de que solo desee cambiar el valor de un elemento, puede usar la función de búsqueda :

// 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
fuente
14

Dado un objeto cambiado y una matriz:

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

Actualice la matriz con el nuevo objeto iterando sobre la matriz:

items = items.map(x => (x.id === item.id) ? item : x)
Extraño compañero
fuente
Por favor, no solo pegue el código. Explica qué se está haciendo y cómo esto resuelve el problema.
Spencer el
1
Creo que esta es la mejor solución ya que es tiene el mejor rendimiento ya que ir por el array sólo una vez y también cambiar la referencia de la matriz, por lo que evitará situaciones mutables
Ohad Sadan
6

Se puede utilizar 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);

Matriz [Object {id: 0}, Object {id: 12345}, Object {id: 2}]

katwal-Dipak
fuente
Me gusta el filtro porque permite crear una nueva matriz y para esto también las entradas que no existen se 'eliminan'
pungggi
0

trabajó para mi

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

returnPayments[this.payments.findIndex(x => x.id == this.payment.id)] = this.payment;
Daniel Laera
fuente
1
Por favor, no solo pegue el código. Explica qué se está haciendo y cómo esto resuelve el problema.
Adrian Mole
La respuesta más votada aceptada no es muy diferente, pero no apuntaste a que actualizaran la respuesta ... ¿por qué es eso?
li x
0

Mientras que la mayoría de las respuestas existentes son geniales, me gustaría incluir una respuesta usando un bucle for tradicional, que también debería considerarse aquí. El OP solicita una respuesta que es compatible con ES5 / ES6, y se aplica el bucle for tradicional :)

El problema con el uso de funciones de matriz en este escenario es que no mutan objetos, pero en este caso, la mutación es un requisito. La ganancia de rendimiento del uso de un bucle for tradicional es solo una bonificación (enorme).

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

Aunque soy un gran admirador de las funciones de matriz, no permita que sean la única herramienta en su caja de herramientas. Si el propósito es mutar la matriz, no son la mejor opción.

Jørgen
fuente
0

One-liner con operador de propagación.

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