web-dev-qa-db-fra.com

Remplacer l'élément à une position spécifique dans un tableau sans le muter

Comment effectuer l'opération suivante sans muter le tableau:

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

Dans le code ci-dessus, la variable array est mutée. Comment puis-je effectuer la même opération sans muter la baie?

28
Bless

Vous pouvez utiliser Object.assign:

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

Vous pouvez simplement configurer un nouveau tableau en tant que tel:

const newItemArray = array.slice();

Et puis définissez la valeur de l'index pour lequel vous souhaitez avoir une valeur.

newItemArray[position] = newItem

et retournez-le. Les valeurs sous les index intermédiaires auront undefined.

Ou l'alternative évidente serait:

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

Eh bien, techniquement, ce ne serait pas remplacer car il n'y a pas d'élément à l'index que vous modifiez.

Regardez comment cela est géré dans Clojure, un langage construit autour d'implémentations canoniques pour des structures de données immuables.

(assoc [1] 2 3)
;; IndexOutOfBoundsException

Non seulement il échoue, mais il se bloque également. Ces structures de données sont conçues pour être aussi robustes que possible et lorsque vous rencontrez ce type d'erreurs, ce n'est généralement pas parce que vous avez découvert un cas Edge, mais plus probablement que vous utilisez la mauvaise structure de données.

Si vous vous retrouvez avec des tableaux clairsemés, envisagez plutôt de les modéliser avec des objets ou des cartes.

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}

Cependant, Map est une structure de données fondamentalement mutable, vous devez donc l'échanger contre une variante immuable avec une bibliothèque comme Immutable.js ou 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}

Bien sûr, il pourrait y avoir une bonne raison de vouloir utiliser les tableaux de JavaScript, alors voici une solution pour faire bonne mesure.

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

La manière rapide

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

Voir le JSPerf (merci à @ Bless )

Articles Similaires:

4
Yves M.

Voici comment j'aimerais le faire:

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

En règle générale, l'opération de répartition sur tableau produit peu de tableaux temporaires pour vous, mais pas map, ce qui peut être plus rapide. Vous pouvez également regarder cette discussion comme référence

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

C'est ce que tu veux?

1
YSJ

Une autre façon pourrait être d'utiliser l'opérateur d'étalement avec une tranche comme

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