Javascript ES6 / ES5 encontrar na matriz e alterar


133

Eu tenho uma variedade de objetos. Quero encontrar por algum campo e depois alterá-lo:

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

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

Eu quero que ele mude o objeto original. Quão? (Eu não me importo se ele estará em Lodash também)


O seu novo objeto itemcontém uma idchave? ou você se importa de ter o ID e todas as propriedades do itemobjeto na entrada da matriz?
Koushik Chatterjee

Respostas:


251

Você pode usar o findIndex para encontrar o índice na matriz do objeto e substituí-lo conforme necessário:

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

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

Isso pressupõe IDs exclusivos. Se seus IDs forem duplicados (como no exemplo), provavelmente será melhor se você usar forEach:

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

16
@georg Isso retornaria uma nova matriz embora.
CodingIntrigue 04/02

3
A função => não funcionará no IE11. Recentemente mordido por isso.
Cianci Lewis

1
pode ser que seria melhor usar letpalavra-chave em vez devar
Inus Saha

Apenas FYI, isso não funciona em algumas versões do phantomJS #
Sid Sid

1
Prefiro o método mais detalhado que o @CodingIntrigue usa em vez de usar o one-liner mapusado pelo @georg. Menos ginástica mental é necessária para descobrir o que está acontecendo. Vale a linha extra de código.
Joshua Pinter

44

Minha melhor abordagem é:

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

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

Referência para findIndex

E caso você não queira substituir por um novo objeto, mas copiar os campos de item, você pode usar Object.assign:

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

como uma alternativa com .map():

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

Abordagem funcional :

Não modifique a matriz, use uma nova para não gerar efeitos colaterais

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

1
Faça o link para uma página em inglês se a pergunta original estiver em inglês. Além disso, este exemplo supõe que o objeto seja sempre encontrado.
raarts #

1
Você sempre pode envolvê-lo em uma expressão try catch, então ... certo?
Soldeplata Saketos

1
E, sendo completamente literal para a pergunta das postagens, ele deseja editar um elemento em uma matriz. Ele não quer saber se existe ou não, então assumimos que ele já fez isso antes.
Soldeplata Saketos

@SoldeplataSaketos sim, você poderia envolvê-lo em um try/catch, mas não deveria, porque não encontrar o elemento não é um caso excepcional; é um caso padrão que você deve considerar verificando o valor de retorno findIndexe atualizando apenas a matriz quando o elemento foi encontrado.
Wayne

20

Uma outra abordagem é usar a emenda .

O splice()método altera o conteúdo de uma matriz removendo ou substituindo elementos existentes e / ou adicionando novos elementos no local .

NB: Caso você esteja trabalhando com estruturas reativas, ele atualizará a "visualização", sua matriz "sabendo" que você a atualizou.

Responda :

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 caso você queira alterar apenas o valor de um item, você pode usar a função 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

Dado um objeto alterado e uma matriz:

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

Atualize a matriz com o novo objeto iterando sobre a matriz:

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

Por favor, não basta colar o código. Explique o que está sendo feito e como isso resolve o problema.
Spencer

1
Eu acho que esta é a melhor solução, uma vez que é tem o melhor desempenho, uma vez que passar por cima da matriz apenas uma vez e também alterar a referência da matriz, por isso vai evitar situações mutáveis
Ohad Sadan

6

Pode ser usado 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 [Objeto {id: 0}, Objeto {id: 12345}, Objeto {id: 2}]


Eu gosto de filtro porque ele permite criar uma nova matriz e, para isso, também as entradas inexistentes são 'excluídas'
pungggi

0

trabalhou para mim

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

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

1
Por favor, não basta colar o código. Explique o que está sendo feito e como isso resolve o problema.
Adrian Mole

A resposta mais votada aceita não é muito diferente, mas você não apontou para eles atualizando a resposta. Por que isso?
li x

0

Enquanto a maioria das respostas existentes é ótima, eu gostaria de incluir uma resposta usando um loop for tradicional, que também deve ser considerado aqui. O OP solicita uma resposta compatível com ES5 / ES6 e o ​​loop for tradicional se aplica :)

O problema com o uso de funções de matriz nesse cenário é que elas não mudam objetos, mas nesse caso, a mutação é um requisito. O ganho de desempenho do uso de um loop for tradicional é apenas um bônus (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;
  }
}

Embora eu seja um grande fã de funções de matriz, não deixe que elas sejam a única ferramenta na sua caixa de ferramentas. Se o objetivo é alterar a matriz, eles não são os mais adequados.


0

Uma linha usando o operador de propagação.

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.