移动类型 Javascript 数组的值?

Shift values of typed Javascript array?

我有一个类型化的 Javascript 数组 (Float32Array),我想在数组的开头一次插入一个值,并将所有其他值移动一个位置(最后一个值被删除)。

这是一个例子:
假设我已经初始化了大小为 3 的数组。 该数组当前包含值 [2.0, 7.2, 4.5],我想插入数字 8.1。结果应该是 [8.1, 2.0, 7.2].

如果我使用普通的 JS 数组,这没问题——我可以使用像 .unshift().pop() 这样的函数,但这些方法不适用于类型化的 JS 数组,因为它们会改变数组的大小.

有没有一种方法可以使用类型化 Javascript 数组有效地实现这一点?

您可以通过将末尾的所有值向右移动 1 来“取消移动”固定数组上的值。完成后,只需将 head 替换为 value 参数即可。传统的 for-loops 将是最有效的方法。

这里的关键是向后循环,用左边的邻居填充最后一个槽。

适用于所有 indexed collections:

  • Array
  • Int8ArrayUint8ArrayUint8ClampedArray
  • Int16ArrayUint16Array
  • Int32ArrayUint32Array
  • Float32Array, Float64Array
  • BigInt64ArrayBigUint64Array

如您所知,TypedArray 对象不具备标准 Array 对象的所有可用方法。

const shiftRight = (collection, value) => {
  for (let i = collection.length - 1; i > 0; i--) {
    collection[i] = collection[i - 1]; // Shift right
  }
  collection[0] = value; // Place new value at head
  return collection;
}

const shiftLeft = (collection, value) => {
  for (let i = 0; i < collection.length - 1; i++) {
    collection[i] = collection[i + 1]; // Shift left
  }
  collection[collection.length - 1] = value; // Place new value at tail
  return collection;
}

const float32 = new Float32Array([2.0, 7.2, 4.5]);

console.log(shiftRight(float32, 8.1)); // >>> [ 8.1, 2.0, 7.2 ]
console.log(shiftLeft(float32, 4.5));  // <<< [ 2.0, 7.2, 4.5 ]
.as-console-wrapper { top: 0; max-height: 100% !important; }

通常你不想用额外的方法污染原型,但如果你到处调用它,你可以设计如下:

shiftRight=(c,v)=>{for(i=c.length-1;i>0;i--)c[i]=c[i-1];c[0]=v;return c}
shiftLeft=(c,v)=>{for(i=0;i<c.length-1;i++)c[i]=c[i+1];c[c.length-1]=v;return c}

/* Needs to be added to all the various indexed collections */
if (Float32Array.prototype.shiftRight === undefined) {
  Float32Array.prototype.shiftRight = function(value) {
    return shiftRight(this, value);
  };
}
if (Float32Array.prototype.shiftLeft === undefined) {  
  Float32Array.prototype.shiftLeft = function(value) {
    return shiftLeft(this, value);
  };
}

const float32 = new Float32Array([2.0, 7.2, 4.5]);

console.log([...float32.shiftRight(8.1).values()]); // >>> [ 8.1, 2.0, 7.2 ]
console.log([...float32.shiftLeft(4.5).values()]);  // <<< [ 2.0, 7.2, 4.5 ]
.as-console-wrapper { top: 0; max-height: 100% !important; }

这是一个不涉及使用循环的方法(在你这边)。

  • 使用子数组使用相同的底层 ArrayBuffer 而不是分配新缓冲区
  • 与 Polywhirl 先生相比,这两个函数只是将值移动任意数量的步骤,不涉及插入任何值,因为我认为这也可以使其他用例受益,并使这两个函数更多“纯的”。所以它更适合名字 shift Left/Right
  • 子数组+集合+填充faster/more内存友好吗?我不知道

const shiftRight = (collection, steps = 1) => {
  collection.set(collection.subarray(0, -steps), steps)
  collection.fill(0, 0, steps)
  return collection
}

const shiftLeft = (collection, steps = 1) => {
  collection.set(collection.subarray(steps))
  collection.fill(0, -steps)
  return collection
}

const float32 = new Float32Array([2.0, 7.2, 4.5]);

shiftRight(float32) // >>> [ 0, 2.0, 7.2 ]
float32[0] = 8.1 // [ 8.1, 2.0, 7.2 ] Place new value at head
console.log(float32)

shiftLeft(float32) // <<< [ 2.0, 7.2, 0 ]
float32.fill(4.5, -1) // [ 2.0, 7.2, 4.5 ] Place new value at tail
console.log(float32)

shiftRight(float32, 2) // >>> [ 0, 0, 2.0 ] shift right 2 steps
console.log(float32)