Javascript ES6 / ES5 znaleźć w tablicy i zmienić


133

Mam tablicę obiektów. Chcę znaleźć według jakiegoś pola, a następnie to zmienić:

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

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

Chcę, aby zmienił oryginalny obiekt. W jaki sposób? (Nie obchodzi mnie, czy to też będzie w lodaszu)


Czy twój nowszy obiekt itemzawiera idklucz? czy może wolisz mieć identyfikator, a także wszystkie właściwości itemobiektu we wpisie tablicy?
Koushik Chatterjee

Odpowiedzi:


251

Możesz użyć findIndex, aby znaleźć indeks w tablicy obiektu i zastąpić go zgodnie z wymaganiami:

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

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

Zakłada się unikalne identyfikatory. Jeśli twoje identyfikatory są zduplikowane (jak w twoim przykładzie), prawdopodobnie lepiej będzie, jeśli użyjesz forEach:

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

16
@georg To jednak zwróci nową tablicę.
CodingIntrigue

3
Funkcja => nie będzie działać w IE11. Niedawno ugryziony przez to.
Lewis Cianci

1
być może lepiej byłoby użyć letsłowa kluczowego zamiastvar
Inus Saha

Do Twojej wiadomości, to nie działa w niektórych wersjach phantomJS
Sid

1
Wolę bardziej rozwlekłą metodę, której używa @CodingIntrigue, zamiast używania jednej maplinijki, której używa @georg. Aby dowiedzieć się, co się dzieje, potrzeba mniej gimnastyki umysłowej. Warte dodatkowej linii kodu.
Joshua Pinter,

44

Moje najlepsze podejście to:

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

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

Odniesienie do findIndex

A jeśli nie chcesz zastąpić nowym obiektem, ale zamiast tego skopiować pola item, możesz użyć Object.assign:

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

jako alternatywa dla .map():

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

Podejście funkcjonalne :

Nie modyfikuj tablicy, użyj nowej, aby nie generować efektów ubocznych

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

1
Podaj link do strony w języku angielskim, jeśli oryginalne pytanie było w języku angielskim. W tym przykładzie przyjęto również, że obiekt jest zawsze znaleziony.
raarts

1
Zawsze możesz zawrzeć to w wyrażeniu try catch, a następnie ... prawda?
Soldeplata Saketos,

1
Będąc całkowicie dosłownym pytaniem postów, chce edytować element w tablicy. Nie chce wiedzieć, czy istnieje, czy nie, więc zakładamy, że zrobił to już wcześniej.
Soldeplata Saketos

@SoldeplataSaketos tak, można by to opakować w a try/catch, ale nie powinno się, bo nie odnalezienie elementu nie jest przypadkiem wyjątkowym; jest to standardowy przypadek, który należy wziąć pod uwagę, sprawdzając zwracaną wartość, findIndexa następnie aktualizując tablicę dopiero po znalezieniu elementu.
Wayne

20

Innym podejściem jest użycie złącza .

splice()Sposób zmienia zawartość tablicy poprzez usunięcie lub zastąpienie istniejących elementów i / lub dodania nowych elementów w miejscu .

NB: Jeśli pracujesz z reaktywnymi frameworkami, zaktualizuje on „widok”, a twoja tablica „wiedząc”, że ją zaktualizowałeś.

Odpowiedź :

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

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

A jeśli chcesz zmienić tylko wartość elementu, możesz użyć funkcji wyszukiwania :

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

Biorąc pod uwagę zmieniony obiekt i tablicę:

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

Zaktualizuj tablicę nowym obiektem, wykonując iterację po tablicy:

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

Nie wklejaj tylko kodu. Wyjaśnij, co się dzieje i jak to rozwiązuje problem.
Spencer

1
Myślę, że jest to najlepsze rozwiązanie, ponieważ ma najlepszą wydajność, ponieważ przechodzi przez tablicę tylko raz, a także zmienia odniesienie tablicy, więc pozwoli uniknąć zmiennych sytuacji
Ohad Sadan

6

Można użyć filtra .

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

Tablica [obiekt {id: 0}, obiekt {id: 12345}, obiekt {id: 2}]


Podoba mi się filtr, ponieważ pozwala stworzyć nową tablicę i do tego również nieistniejące wpisy są
``

0

pracował dla mnie

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

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

1
Nie wklejaj tylko kodu. Wyjaśnij, co się dzieje i jak to rozwiązuje problem.
Adrian Mole

Przyjęta najbardziej pozytywna odpowiedź nie różni się zbytnio, ale nie wskazałeś, że aktualizują tam odpowiedź ... dlaczego tak jest?
li x

0

Podczas gdy większość istniejących odpowiedzi jest świetnych, chciałbym dołączyć odpowiedź za pomocą tradycyjnej pętli for, którą również należy wziąć pod uwagę. OP żąda odpowiedzi zgodnej z ES5 / ES6 i obowiązuje tradycyjna pętla for :)

Problem z używaniem funkcji tablicowych w tym scenariuszu polega na tym, że nie mutują one obiektów, ale w tym przypadku mutacja jest wymagana. Wzrost wydajności wynikający z używania tradycyjnej pętli for to tylko (ogromny) 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;
  }
}

Chociaż jestem wielkim fanem funkcji tablicowych, nie pozwól, aby były one jedynym narzędziem w Twoim zestawie narzędzi. Jeśli celem jest mutowanie tablicy, nie są one najlepiej dopasowane.


0

Jednowierszowy z operatorem rozprzestrzeniania.

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.