在一个数组中,是否有一种函数可以将一组元素复制到另一个数组的范围内?

7

我在我的javascript代码中有一个地方需要执行如下操作:

将一个数组的指定范围复制到另一个数组的指定范围。

这个操作类似于

1)Java中的System.arraycopy ->

System.arraycopy(array1, index1, array2, index3, index4 - index4 + 1);

2) Go 中的 copy 方法:

copy(array2[index3:index4 + 1], array1[index1:index2+1])

3) Python 中的切片操作:

array2[index3: index4 + 1] = arr[index1: index2+1]

目前我是手动迭代并执行此操作。

但是我没有在JavaScript中找到任何工具函数来执行此操作。真的有这样的吗?

更新1:它应该精确地复制,而不添加或删除任何两个给定数组中的元素。

它应该像这个实现一样运行:

function arraycopy(src, srcPos, dst, dstPos, length) {
    let j = dstPos;
    let tempArr = src.slice(srcPos, srcPos + length);
    for (let e in tempArr) {
        dst[j] =  tempArr[e];
        j++;
    }
};

更新2:(请小心查看下面的一些答案,看看它是否适用于您的用例(例如在大型数据集的情况下))许多下面的答案使用splice的方式会破坏它,如果源数组的范围从开始到结尾很大。它将抛出“RangeError:Maximum call stack size exceeded”……因为它将超过函数允许的最大参数数量。 (在这里尝试演示脚本)"


您可以使用.splice.slice来拼接切片。 - Aluan Haddad
如果这有帮助的话,你可以看一下我的答案,基本上是使用切片和连接函数来模仿Python函数。 - jazz
我在我的答案中添加了一个帮助函数,它使用 concat() 来解决 RangeError 问题,并返回一个新的数组,其中输入数组不会被改变。 - Tim Klein
7个回答

3

结合使用 slicesplice 可能是解决问题的方法。您可以编写一个辅助函数来模仿其他语言中的相同行为。这里有一个与 Java 的 arraycopy 方法相似的函数:

const arr1 = [1, 2, 3, 4, 5, 6];
const arr2 = ["a", "b", "c", "d", "e", "f"];

function arrayCopy(src, srcIndex, dest, destIndex, length) {
  dest.splice(destIndex, length, ...src.slice(srcIndex, srcIndex + length));
}

// copy from arr1, at position 0, into arr2, at position 2, 3 elements.
arrayCopy(arr1, 0, arr2, 2, 3);
console.log(arr2)


警告:我們不應該使用這種方法,因為如果源數組中的範圍開始到結束很大,它將會崩潰。它會拋出“RangeError:Maximum call stack size exceeded”,因為它超過了函數允許的最大參數。(stackoverflow.com/a/44978433/1597944) - Harish Kayarohanam
这不适用于像Int8Array这样的类型化数组。 - neoexpert

2

在JavaScript中没有类似的东西。可能有一些具有类似功能的JavaScript库,但我不知道。简单的循环和赋值会更加高效,因为它避免了函数调用和创建新数组所带来的开销:

function arraycopy(src, srcPos, dst, dstPos, length) {
    while (length--) dst[dstPos++] = src[srcPos++]; return dst;
}

console.log( arraycopy([2,3,4,5,6], 1, [1,1,1,1,1,1], 2, 3) )

另一种效率低下的完整性解决方案是使用Object.assign复制值:

function arraycopy(src, srcPos, dst, dstPos, length) {
    return Object.assign(dst, Array(dstPos).concat(src.slice(srcPos, srcPos + length)))
}

console.log( arraycopy([2,3,4,5,6], 1, [1,1,1,1,1,1], 2, 3) )


1
另一种方法是使用slice从源数组中剪切出所需的元素(而不改变它),然后使用forEach用剪切出的元素替换目标数组中的元素:
function arraycopy(src, srcPos, dst, dstPos, length) {
    src.slice(srcPos, srPos + length)
       .forEach((e, i) => dst[dstPos + i] = e);
}

例子:

function arraycopy(src, srcPos, dst, dstPos, length) {
    src.slice(srcPos, srcPos + length)
       .forEach((e, i) => dst[dstPos + i] = e);
}

let arr1 = [0, 1, 2, 3, 4, 5, 6];
let arr2 = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

arraycopy(arr1, 2, arr2, 3, 3);

console.log("arr1: " + arr1);
console.log("arr2: " + arr2);


1
我不知道有任何一个函数可以做到这一点,但是我认为可以使用 slice()splice() 方法来实现这个功能。

slice() 方法将数组的一部分切出并创建成一个新的数组。

splice() 方法可以用来向数组中添加新的元素。


1
你可以使用Array.prototype.splice()方法(以及Array.prototype.slice()方法)来实现你所描述的功能。
比如说,你想将数组A中从索引3到5(包括3和5)的元素复制到数组B的索引3处(替换B中索引3到5的任何内容):

const A = [0, 1, 2, 3, 4, 5, 6];
const B = ['a', 'b', 'c', 'd'];

const start = 3;
const end = 6;

// Splice (end - start) elements starting at 3
// with elements from start to end in A
B.splice(3, end - start, ...A.slice(start, end));

console.log(B);

注意:这也利用了JavaScript的展开操作符,该操作符会发出由A.slice()返回的数组中的所有单个值。
编辑
考虑以下内容:

更新 1:它应该仅精确地复制而不是添加或删除任何两个给定数组之一中的元素。

......如果源数组中的范围从开始到结束很大,它将会中断。

考虑以下函数:

function arrayCopy(arr1, index1, arr2, index2, length) {
    return []
        .concat(arr2.slice(0, index2))                  // Array 2 from beginning until the index to replace
        .concat(arr1.slice(index1, index1 + length))    // Array 1 from the index to copy for 'length' elements
        .concat(arr2.slice(index2 + length));           // Rest of Array 2, 'length' elements past the index to replace
}

const A = [0, 1, 2, 3, 4, 5, 6];
const B = ['a', 'b', 'c', 'd'];

// Copy B into Z and replace Z[3] to Z[5] with A[3] to A[5]
const Z = arrayCopy(A, 3, B, 3, 3);

console.log('\'A\' after copy:');
console.log(A);
console.log('\'B\' after copy:');
console.log(B);
console.log('\'Z\' after copy:');
console.log(Z);

// Testing the method with arrays of length 2,000,000

const longArray = [];
const otherLongArray = [];

for (let i = 0; i < 2000000; i++) {
    longArray.push(i);
    otherLongArray.push(-i);
}

const newLongArray = arrayCopy(longArray, 0, otherLongArray, 1500000, 1000000);

console.log(newLongArray.length);

这将创建一个新的数组,该数组是第二个输入数组的副本,但会用第一个输入数组(从index1开始)的length个元素替换该数组中的length个元素(从index2开始)。该函数利用Array.prototype.concat(),它将完整的数组作为参数。当数组非常大时,这应该可以缓解“调用堆栈”错误问题。

你的代码在索引处插入元素。它应该替换该索引内的元素。就像Java中的arraycopy一样。 - Harish Kayarohanam
1
请查看我编辑后的代码片段进行替换,而不是简单地注入。 - Tim Klein
警告:我們不應該使用這種方法,因為如果源數組中的範圍開始到結束很大,它將會崩潰。它會拋出“RangeError:Maximum call stack size exceeded”,因為它超過了函數允許的最大參數。(https://stackoverflow.com/a/44978433/1597944) - Harish Kayarohanam
请查看我的#编辑,以解决“RangeError”问题。 - Tim Klein

0

JavaScript数组的slice()和concat()方法符合您的要求。

var arr= ["a", "b", "c", "d", "e"];
var arr2 = ["x","y","z"];
arr= arr.slice(0, index3).concat(arr2.slice(index1: index2+1)).concat(arr.slice(index4+1, arr.length));

试用HTML文件


0

您可以使用slice方法将一个数组的一段元素复制到另一个数组中,同时保持原始数组不变。

slice方法接受两个参数,第一个参数是复制操作的起始索引,第二个参数是复制操作的结束索引结束索引不包括在结果数组中。

以下是说明的示意图:

var arr1 = ['Hi ', 'there! ', 'How ', 'are ', 'you ?'];
var arr2 = arr1.slice(2, arr1.length);
console.log(arr2.toString());
// output: How ,are ,you ?

了解更多关于 slice 方法的信息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接