Подтвердить что ты не робот

Заменить элемент в определенном месте в массиве без его изменения

Как выполнить следующую операцию без изменения массива:

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

В приведенном выше коде переменная array видоизменена. Как я могу выполнить ту же операцию, не изменяя массив?

4b9b3361

Ответ 1

Вы можете использовать Object.assign:

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

Ответ 2

Вы можете просто создать новый массив как таковой:

const newItemArray = array.slice();

И затем установите значение для индекса, для которого вы хотите иметь значение.

newItemArray[position] = newItem

и вернуть это. Значения под промежуточными индексами будут иметь undefined.

Или, очевидно, альтернативой будет:

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

Ответ 3

Ну, технически это не заменит, поскольку в индексе, который вы меняете, нет элемента.

Посмотрите, как это происходит в Clojure - языке, построенном вокруг канонических реализаций для неизменных структур данных.

(assoc [1] 2 3)
;; IndexOutOfBoundsException

Он не только терпит неудачу, но и падает. Эти структуры данных спроектированы так, чтобы быть максимально надежными, и когда вы сталкиваетесь с подобными ошибками, обычно это происходит не потому, что вы обнаружили крайний случай, а с большей вероятностью, что вы используете неправильную структуру данных.

Если у вас получаются разреженные массивы, рассмотрите возможность моделирования их с помощью объектов или карт.

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

Ответ 5

Вот как я хотел бы это сделать:

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

Как правило, операция с расширением массива создает для вас несколько временных массивов, но map не работает, поэтому может быть быстрее. Вы также можете посмотреть это обсуждение в качестве ссылки

Ответ 6

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

Ответ 7

Другим способом может быть использование оператора распространения со слайсом как

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]