web-dev-qa-db-ja.com

配列内の特定の位置にある要素を変更せずに置き換えます

配列を変更せずに次の操作を実行するにはどうすればよいですか:

let array = ['item1'];
console.log(array); // ['item1']
array[2] = 'item2'; // array is mutated
console.log(array); // ['item1', undefined, 'item2']

上記のコードでは、array変数が変更されています。配列を変更せずに同じ操作を実行するにはどうすればよいですか?

28
Bless

Object.assignを使用できます:

Object.assign([], array, {2: newItem});
57
Oriol

次のような新しい配列を設定するだけです。

const newItemArray = array.slice();

そして、値を取得したいインデックスの値を設定します。

newItemArray[position] = newItem

そしてそれを返します。中間のインデックスの下の値はundefinedになります。

または、明らかに代替案は次のとおりです。

Object.assign([], array, {<position_here>: newItem});
7
Elod Szopos

技術的には、これはreplaceingではありません。変更するインデックスにはアイテムがありません。

Clojure(不変データ構造の標準的な実装を中心に構築された言語)での処理方法を見てください。

(assoc [1] 2 3)
;; IndexOutOfBoundsException

失敗するだけでなく、クラッシュします。これらのデータ構造は可能な限り堅牢になるように設計されており、これらの種類のエラーに出くわすのは、通常、Edgeのケースを発見したからではなく、間違ったデータ構造を使用している可能性が高いからです。

スパース配列で終わる場合は、代わりにオブジェクトまたはマップを使用してそれらをモデリングすることを検討してください。

let items = { 0: 1 };
{ ...items, 2: 3 };
// => { 0: 1, 2: 3 }

let items = new Map([ [0, 1] ]);
items(2, 3);
// => Map {0 => 1, 2 => 3}

ただし、Mapは基本的に変更可能なデータ構造であるため、 Immutable.js または Mori のようなライブラリを使用して、これを不変のバリアントに交換する必要があります。

let items = Immutable.Map([ [0, 2] ]);
items.set(2, 3);
// => Immutable.Map {0 => 1, 2 => 3}

let items = mori.hashMap();
mori.assoc(items, 2, 3);
// => mori.hashMap {0 => 1, 2 => 3}

もちろん、JavaScriptの配列を使用したい理由は完全にあるかもしれないので、ここでは適切な測定のためのソリューションを示します。

function set(arr, index, val) {
  if(index < arr.length) {
    return [
      ...arr.slice(0, position),
      val,
      ...arr.slice(position + 1)
    ];
  } else {
    return [
      ...arr,
      ...Array(index - arr.length),
      val
    ];
  }
}
7
Dan Prince

fast方法

function replaceAt(array, index, value) {
  const ret = array.slice(0);
  ret[index] = value;
  return ret;
}

JSPerf@ Bless に感謝)を参照してください

関連記事:

4
Yves M.

ここに私がそれをやりたい方法があります:

function update(array, newItem, atIndex) {
    return array.map((item, index) => index === atIndex ? newItem : item);
}

一般的に、Array-spread操作は一時的な配列をほとんど生成しませんが、mapは生成しないため、高速になります。また、参照として この説明 を参照することもできます。

2
just-boris
var list1 = ['a','b','c'];
var list2 = list1.slice();
list2.splice(2, 0, "beta", "gamma");
console.log(list1);
console.log(list2);

これは、あなたの望むことですか?

1
YSJ

別の方法は、次のようにスライスでスプレッド演算子を使用することです

let newVal = 33, position = 3;
let arr = [1,2,3,4,5];
let newArr = [...arr.slice(0,position - 1), newVal, ...arr.slice(position)];
console.log(newArr); //logs [1, 2, 33, 4, 5]
console.log(arr); //logs [1, 2, 3, 4, 5]
0
Saksham