替换元素中特定位置的元素而不改变它

Ble*_*ess 31 javascript arrays immutability ecmascript-6

如何在不改变数组的情况下完成以下操作:

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

在上面的代码中,array变量是变异的.如何在不改变阵列的情况下执行相同的操作?

Ori*_*iol 66

你可以使用Object.assign:

Object.assign([], array, {2: newItem});
Run Code Online (Sandbox Code Playgroud)

  • @ cemper93它可以工作,你只需要使用这个特定的语法:`Object.assign([],array,{[i]:newItem})` (11认同)
  • 也就是说,使用`slice`复制数组可能会更快,因为首先复制`length`,因此预分配是可能的.`Object.assign(array.slice(),{2:newItem});`是另一种可能性. (4认同)
  • @DanPrince不确定如何实现这些共享结构.但是slice会复制整个数组,因此case也是O(n). (2认同)

Yve*_* M. 12

快速

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

请参阅JSPerf(感谢@Bless

相关文章:


Elo*_*pos 7

你可以简单地设置一个新的数组:

const newItemArray = array.slice();
Run Code Online (Sandbox Code Playgroud)

然后为您希望拥有值的索引设置值.

newItemArray[position] = newItem
Run Code Online (Sandbox Code Playgroud)

并返回.中间索引下的值将具有undefined.

或明显的替代方案是:

Object.assign([], array, {<position_here>: newItem});
Run Code Online (Sandbox Code Playgroud)


Dan*_*nce 7

好吧,从技术上讲,这不会被替换,因为您正在更改的索引中没有项目.

看看它是如何在Clojure中处理的 - 这是一种围绕不可变数据结构的规范实现构建的语言.

(assoc [1] 2 3)
;; IndexOutOfBoundsException
Run Code Online (Sandbox Code Playgroud)

它不仅失败了,而且崩溃了.这些数据结构设计得尽可能健壮,当您遇到这些类型的错误时,通常不是因为您发现了边缘情况,而更可能是您使用了错误的数据结构.

如果您要使用稀疏数组,那么请考虑使用对象或贴图对它们进行建模.

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}
Run Code Online (Sandbox Code Playgroud)

但是,Map是一个根本可变的数据结构,所以你需要将它与一个像Immutable.jsMori这样的库的不可变变量交换掉.

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}
Run Code Online (Sandbox Code Playgroud)

当然,想要使用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
    ];
  }
}
Run Code Online (Sandbox Code Playgroud)


Sak*_*ham 6

另一种方法可能是使用扩展运算符和切片作为

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]
Run Code Online (Sandbox Code Playgroud)


jus*_*ris 5

这是我想怎么做:

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

通常,数组扩展操作为您生成很少的临时数组,但map不会,因此它可以更快。你也可以看看这个讨论作为参考