JavaScript ES6 / ES5は配列内で検索して変更します


133

オブジェクトの配列があります。いくつかのフィールドで検索し、それを変更したい:

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

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

元のオブジェクトを変更したい。どうやって?(それがロダッシュでもかまいません)


新しいオブジェクトitemidキーが含まれていますか?またはitem、配列のエントリにオブジェクトのIDとすべてのプロパティがあることを気にしますか?
Koushik Chatterjee

回答:


250

findIndexを使用して、オブジェクトの配列内のインデックスを検索し、必要に応じて置き換えることができます。

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

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

これは一意のIDを想定しています。(例のように)IDが重複している場合は、forEachを使用した方がよいでしょう。

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

16
@georgそれでも新しい配列を返します。
CodingIntrigue 2016

3
=>関数はIE11では機能しません。最近これに噛まれました。
ルイスチャンチ

1
let代わりにキーワードを使用した方がよい場合がありますvar
Inus Saha

参考までに、これはphantomJSの一部のバージョンでは機能しません
Sid

1
@georgが使用するワンライナーを使用するよりも、@ CodingIntrigueが使用するより冗長な方法を好みmapます。何が起こっているのかを理解するために必要なより少ない精神体操。余分なコード行の価値があります。
ジョシュアピンター2018

44

私の最善のアプローチは:

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

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

findIndexのリファレンス

また、新しいオブジェクトに置き換えたくない場合は、代わりにのフィールドをコピーするにはitem、次のように使用できますObject.assign

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

の代替として.map()

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

機能的アプローチ

配列を変更せず、新しい配列を使用して、副作用を発生させない

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

1
元の質問が英語であった場合は、英語のページにリンクしてください。また、この例では、オブジェクトが常に検出されることを前提としています。
raarts 2017

1
いつでもそれをtry catch式でラップできます...そうですか?
Soldeplata Saketos 2017

1
そして、投稿の質問に対して完全に文字通り、彼は配列の要素を編集したいと考えています。彼はそれが存在するかどうかを知りたくないので、私たちは彼が以前にそれをすでにしたと仮定します。
Soldeplata Saketos

@SoldeplataSaketosはい、要素をでラップすることはできますtry/catch、要素を見つけられないことは例外的なケースではないため、ラップしないでください。これは、戻り値を確認しfindIndex、要素が見つかった場合にのみ配列を更新することで説明する必要がある標準的なケースです。
ウェイン

20

別のアプローチは、スプライスを使用することです。

このsplice()メソッドは、既存の要素を削除または置換したり、新しい要素適切な場所に追加したりして、配列の内容を変更します。

注意:リアクティブフレームワークを使用している場合は、「ビュー」が更新され、配列は更新したことを「認識」します。

答え:

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

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

また、アイテムの値のみを変更する場合は、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

変更されたオブジェクトと配列が与えられた場合:

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

配列を反復処理して、配列を新しいオブジェクトで更新します。

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

コードを貼り付けないでください。何が行われていて、これがどのように問題を解決するかを説明します。
スペンサー、

1
これは、アレイを1度だけ通過し、アレイの参照も変更するため、最高のパフォーマンスを発揮し、変更可能な状況を回避できるため、最良のソリューションであると思います
Ohad Sadan

6

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

配列[オブジェクト{id:0}、オブジェクト{id:12345}、オブジェクト{id:2}]


新しい配列を作成することができ、これも存在しないエントリが「削除」されるため、私はフィルターが好きです
pungggi

0

私のために働いた

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

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

1
コードを貼り付けないでください。何が行われていて、これがどのように問題を解決するかを説明します。
Adrian Mole

受け入れられた最も賛成された答えはそれほど変わらないが、あなたは彼らがそこに答えを更新することを指摘しなかった。
li x

0

既存の回答のほとんどはすばらしいものですが、ここでも考慮すべき従来のforループを使用した回答を含めたいと思います。OPはES5 / ES6互換の回答を要求し、従来のforループが適用されます:)

このシナリオで配列関数を使用する場合の問題は、オブジェクトを変更しないことですが、この場合、変更が必須です。従来のforループを使用することによるパフォーマンスの向上は、(大きな)ボーナスにすぎません。

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

私は配列関数の大ファンですが、それらをツールボックスの唯一のツールにしないでください。目的が配列の変更である場合、それらは最適ではありません。


0

スプレッド演算子を使用したワンライナー。

 const updatedData = originalData.map(x => (x.id === id ? { ...x, updatedField: 1 } : x));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.