배열 항목을 다른 배열로 복사


916

dataArray새 배열로 푸시하려는 JavaScript 배열 이 newArray있습니다. 내가 원하지 않는 제외시켰다 newArray[0]것으로 dataArray. 모든 항목을 새 배열로 푸시하고 싶습니다.

var newArray = [];

newArray.pushValues(dataArray1);
newArray.pushValues(dataArray2);
// ...

또는 더 나은 :

var newArray = new Array (
   dataArray1.values(),
   dataArray2.values(),
   // ... where values() (or something equivalent) would push the individual values into the array, rather than the array itself
);

이제 새 배열에는 개별 데이터 배열의 모든 값이 포함됩니다. pushValues사용할 수있는 것과 같은 속기가 있습니까? 그래서 각 개인을 반복 할 필요 dataArray없이 항목을 하나씩 추가합니까?




답변:


1247

다음과 같이 concat 함수를 사용하십시오 .

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayA.concat(arrayB);

의 값이 newArray될 것이다 [1, 2, 3, 4]( arrayA그리고 arrayB변하지; concat결과를위한 새로운 배열을 생성 및 리턴).



16
나는 수행자 실행이 매우 훌륭하다는 것에 동의합니다. 하지만 대한 CONCAT 정확하지 않습니다 에게 목적 CONCAT 배열에? 따라서 표준 이어야합니다 . 아니면 concat과 관련하여 더 좋은 일이 있습니까? 그리고 브라우저의 JS 엔진이 잘못 구현되었거나 사용하는 곳이 어디에서만 느려질 수 있습니까? 언젠가 고칠 수 있습니다. 해키 속도 최적화보다 코드 유지 관리 성을 선택합니다. 흠 ....
Bitterblue

3
또한 상황을 벤치마킹했습니다 : concat vs. push.apply. Google Chrome: 빠름 (concat = 승자), Opera: 빠름 (concat = 승자), IE: 느림 (concat = 승자), Firefox: 느림 (push.apply = 승자, 크롬의 concat보다 10 배 느림) ... 잘못된 JS 엔진 구현에 대해 이야기 .
Bitterblue

15
두 배열을 연결 하면 어떻게 다른 배열로 밀어 넣을 수 있습니까 ?! 그것들은 두 가지 다른 작업입니다.
kaqqao

@kaqqao push는 값의 배열을 평탄화하지 않기 때문에 . concat질문에 필요한 것을 달성합니다.
WiseGuyEh

644

배열이 크지 않은 경우 (아래주의 사항 참조) push()값을 추가 할 배열 의 방법을 사용할 수 있습니다 . push()여러 매개 변수를 사용할 수 있으므로 해당 apply()메서드를 사용하여 함수 매개 변수 목록으로 푸시 할 값 배열을 전달할 수 있습니다 . 이것은 concat()새로운 배열을 생성하는 대신 배열에 요소를 추가하는 것보다 장점이 있습니다 .

그러나 10 만 명 이상의 대규모 배열의 경우이 트릭이 실패 할 수 있습니다. 이러한 배열의 경우 루프를 사용하는 것이 더 좋습니다. 자세한 내용은 https://stackoverflow.com/a/17368101/96100 을 참조하십시오.

var newArray = [];
newArray.push.apply(newArray, dataArray1);
newArray.push.apply(newArray, dataArray2);

이것을 함수로 일반화하고 싶을 수도 있습니다.

function pushArray(arr, arr2) {
    arr.push.apply(arr, arr2);
}

... 또는 Array프로토 타입에 추가하십시오 .

Array.prototype.pushArray = function(arr) {
    this.push.apply(this, arr);
};

var newArray = [];
newArray.pushArray(dataArray1);
newArray.pushArray(dataArray2);

... 또는 원래 에뮬레이트 push()사실하여 여러 파라미터시킴으로써 방법 concat()push()여러 파라미터를 허용 :

Array.prototype.pushArray = function() {
    this.push.apply(this, this.concat.apply([], arguments));
};

var newArray = [];
newArray.pushArray(dataArray1, dataArray2);

다음 예제는 IE <= 8을 포함하여 모든 대형 브라우저 및 모든 주요 브라우저에 적합한 마지막 예제의 루프 기반 버전입니다.

Array.prototype.pushArray = function() {
    var toPush = this.concat.apply([], arguments);
    for (var i = 0, len = toPush.length; i < len; ++i) {
        this.push(toPush[i]);
    }
};

9
참고 :newArray.push.apply(newArray, dataArray1);Array.prototype.push.applay(newArray,dataArra1);

이전 브라우저와 호환됩니까?
Damien Ó Ceallaigh


1
@ DamienÓCeallaigh : 예. 이것은 모두 IE 6 및 이전 버전으로 돌아가는 브라우저와 호환됩니다.
Tim Down

이것은 나쁜 프로그래밍 관행의 전형입니다. Array.prototype.concat나쁘지 않고 오히려 오해되고 때로는 오용되기도합니다. 이러한 상황에서는 오해 만 있지만 오용되지는 않습니다.
Jack Giffin

444

"미래에 대비 한"답장을 하나 더 추가하겠습니다

ECMAScript 6에서는 Spread 구문을 사용할 수 있습니다 .

let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
arr1.push(...arr2);

console.log(arr1)

스프레드 구문은 아직 모든 주요 브라우저에 포함되어 있지 않습니다. 현재 호환성에 대해서는이 (지속적으로 업데이트 된) 호환성 표를 참조하십시오 .

그러나 Babel.js 와 함께 스프레드 구문을 사용할 수 있습니다 .

편집하다:

성능에 대한 자세한 설명은 아래 Jack Giffin의 답변을 참조하십시오. concat이 스프레드 연산자보다 여전히 낫고 빠릅니다.


7
TypeScript를 사용하는 경우 스프레드 연산자를 사용할 수도 있습니다. ES5를 대상으로하면에 컴파일됩니다 newArray.apply(newArray, dataArray1).
AJ Richardson

5
참고 : 세 번째 배열의 결과가 필요한 경우 (초기 질문이 요구하는 것처럼 arr1을 수정하지 않음) newArray = [... arr1, ... arr2]
dim

아 몰랐어 감사. 편집 의견을 추가했습니다.
Karel Bílek 5

concat이 작동하는 방식과 유사하며, 영구적 인 보너스 (원래 배열을 변경)가 있습니다.
Rob

@robertmylne 스프레드 연산자는 원래 배열을 수정하지 않고 대신 모든 배열 내용의 새 사본을 작성해야합니다.
잭 지핀

145

MDN 에서 우아한 길을 찾았습니다

var vegetables = ['parsnip', 'potato'];
var moreVegs = ['celery', 'beetroot'];

// Merge the second array into the first one
// Equivalent to vegetables.push('celery', 'beetroot');
Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']

또는 spread operatorES6 의 기능을 사용할 수 있습니다 .

let fruits = [ 'apple', 'banana'];
const moreFruits = [ 'orange', 'plum' ];

fruits.push(...moreFruits); // ["apple", "banana", "orange", "plum"]

1
이것은 질문이 요구 한 것이 아닙니다. 문제는 구식 배열을 수정하지 않고 매번 새 배열을 만드는 방법을 요구하는 것입니다.
Jack Giffin

13
var a=new Array('a','b','c');
var b=new Array('d','e','f');
var d=new Array('x','y','z');
var c=a.concat(b,d)

그게 당신의 문제를 해결합니까?


13

다음은 나에게 가장 간단한 것 같습니다.

var newArray = dataArray1.slice();
newArray.push.apply(newArray, dataArray2);

"push"는 가변 개수의 인수를 취 apply하므로 push함수 의 메소드를 사용하여 다른 배열의 모든 요소를 ​​푸시 할 수 있습니다 . 첫 번째 인수 (여기서는 "newArray")를 "this"로, 배열의 요소를 나머지 인수로 사용하여 푸시하는 호출을 구성합니다.

slice첫 번째 문에서 첫 번째 배열의 복사본을 얻는다, 그래서 당신은 그것을 수정하지 마십시오.

업데이트 슬라이스를 사용할 수있는 자바 스크립트 버전을 사용하는 경우 다음과 같이 push표현을 단순화 할 수 있습니다 .

newArray.push(...dataArray2)

1
"두 어레이 병합"에 대한 예제 로 MDN 에서도 언급 됩니다.
Wilt

12

아래 함수는 배열 길이에 문제가 없으며 모든 제안 된 솔루션보다 성능이 우수합니다.

function pushArray(list, other) {
    var len = other.length;
    var start = list.length;
    list.length = start + len;
    for (var i = 0; i < len; i++ , start++) {
        list[start] = other[i];
    }
}

불행히도 jspref는 내 제출을 수락하지 않으므로 다음은 benchmark.js를 사용한 결과입니다.

        Name            |   ops/sec   |  ± %  | runs sampled
for loop and push       |      177506 |  0.92 | 63
Push Apply              |      234280 |  0.77 | 66
spread operator         |      259725 |  0.40 | 67
set length and for loop |      284223 |  0.41 | 66

어디

for 루프 앤 푸시는 다음과 같습니다.

    for (var i = 0, l = source.length; i < l; i++) {
        target.push(source[i]);
    }

적용을 누릅니다.

target.push.apply(target, source);

스프레드 연산자 :

    target.push(...source);

마지막으로 'set length and for loop'는 위의 함수입니다.


이 질문은 기존 배열을 수정하지 않고 매번 새 배열을 만드는 방법을 찾고 있습니다.
잭 지핀

10

𝗥𝗲𝘀𝗲𝗮𝗿𝗰𝗵 𝗔𝗻𝗱 𝗥𝗲𝘀𝘂𝗹𝘁𝘀

사실, jsperf성능 테스트 와 콘솔의 일부 검사가 수행됩니다. 연구를 위해 irt.org 웹 사이트 가 사용됩니다. 아래는 이러한 모든 소스의 모음이며 하단에 예제 기능입니다.

╔ ================ ╦ ====== ╦ =========================== ======== ╦ ========== ╦ ============
║ 방법 ║Concat║slice & push.apply ║ push.apply x2 ║ ForLoop ║Spread ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
Op mOps / Sec 79179 ║104 ║ 76 ║ 81 ║28 ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
par 스파 스 배열 ║ 예! ║ 슬라이스 만 ║ 아니오 ║ 어쩌면 2   ║no ║
spa 스파 스 유지 ║ ║ 배열 (첫 번째 인수) ║ ║ ║ ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
║ 지원 ║MSIE 4║MSIE 5.5║ MSIE 5.5║ MSIE 4║Edge 12║source 
( 출처 ) ║NNav 4║NNav 4.06 ║ NNav 4.06 ║ NNav 3 ║ MSIE  NNav ║
╠ ================ ╬ ====== ╬ =========================== ======== ╬ ========== ╬ ============
║ 배열 같은 행동 ║ 아니오 ║ 누른 ║ 예만! 예! ║있는 경우
║ 배열처럼 ║ (배열 (2 번째 인수) ║ ║ ║ 반복자 1   ║
╚ ================ ╩ ====== ╩ =========================== ======== ╩ ========== ╩ ============
1 배열과 같은 객체에 Symbol.iterator 속성 이없는 경우
  퍼 뜨리면 예외가 발생합니다.
2 코드에 따라 다릅니다. 다음 예제 코드 "YES"는 희소성을 유지합니다.
function mergeCopyTogether(inputOne, inputTwo){
   var oneLen = inputOne.length, twoLen = inputTwo.length;
   var newArr = [], newLen = newArr.length = oneLen + twoLen;
   for (var i=0, tmp=inputOne[0]; i !== oneLen; ++i) {
        tmp = inputOne[i];
        if (tmp !== undefined || inputOne.hasOwnProperty(i)) newArr[i] = tmp;
    }
    for (var two=0; i !== newLen; ++i, ++two) {
        tmp = inputTwo[two];
        if (tmp !== undefined || inputTwo.hasOwnProperty(two)) newArr[i] = tmp;
    }
    return newArr;
}

위에서 볼 수 있듯이, Concat은 거의 항상 성능과 여분의 스페어 어레이를 유지하는 기능을 모두 수행 할 수있는 방법이라고 주장합니다. 그런 다음 배열과 같은 (예 : DOMNodeLists와 같은 document.body.children) for 루프는 두 번째로 성능이 높고 스파 스 배열을 유지하는 유일한 다른 방법이기 때문에 for 루프를 사용하는 것이 좋습니다. 아래에서는 희소 배열 및 배열과 같은 의미를 신속하게 살펴보고 혼란을 해결합니다.

𝗧𝗵𝗲 𝗙𝘂𝘁𝘂𝗿𝗲

처음에 일부 사람들은 이것이 우연이라고 생각할 수 있으며 브라우저 공급 업체는 결국 Array.prototype.push를 Array.prototype.concat을 이길 수있을 정도로 빠르도록 최적화 할 것입니다. 잘못된! Array.prototype.concat은 데이터를 복사하는 간단한 붙여 넣기이므로 항상 원칙적으로 더 빠릅니다. 아래는 32 비트 배열 구현의 모습을 단순화 한 설득력있는 시각적 다이어그램입니다 (실제 구현은 훨씬 더 복잡합니다)

바이트 ║ 여기에 데이터
====== ╬ ============
0x00 ║ int nonNumericPropertiesLength = 0x00000000
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ 정수 길이 = 0x00000001
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ int valueIndex = 0x00000000
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ int valueType = JS_PRIMITIVE_NUMBER
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드
0x00 ║ uintptr_t valuePointer = 0x38d9eb60 (또는 메모리에있는 곳)
0x01 ║ 아이비드
0x02 ║ 아이비드
0x03 ║ 아이비드

위에서 본 것처럼, 이와 같은 것을 복사하기 위해해야 ​​할 일은 바이트 단위로 복사하는 것만큼이나 간단합니다. Array.prototype.push.apply를 사용하면 데이터를 복사하여 붙여 넣기하는 것 이상의 의미를 갖습니다. ".apply"는 Array.prototype.push에 전달하기 전에 배열의 각 인덱스를 확인하여 인수 집합으로 변환해야합니다. 그런 다음 Array.prototype.push는 매번 추가 메모리를 추가로 할당해야하며 (일부 브라우저 구현의 경우) sparseness를 위해 일부 위치 조회 데이터를 다시 계산할 수도 있습니다.

그것을 생각하는 다른 방법은 이것입니다. 소스 배열 1은 큰 용지 묶음입니다. 소스 어레이 2는 또 다른 큰 용지 더미입니다. 당신이 더 빠를까요

  1. 상점에 가서 각 소스 어레이의 사본에 필요한 충분한 용지를 구입하십시오. 그런 다음 각 소스 배열 용지 더미를 복사기를 통해 넣고 결과물 두 장을 스테이플합니다.
  2. 상점에 가서 첫 번째 소스 어레이의 단일 사본에 충분한 용지를 구입하십시오. 그런 다음 빈 배열이 빈 공간이 없도록 수동으로 소스 배열을 새 용지에 복사하십시오. 그런 다음 상점으로 돌아가서 두 번째 소스 배열에 충분한 용지를 구입하십시오. 그런 다음 두 번째 소스 배열을 통해 복사하면서 복사본에 공백이 생기지 않도록 복사하십시오. 그런 다음 복사 된 모든 용지를 함께 스테이플하십시오.

위의 비유에서 옵션 # 1은 Array.prototype.concat을 나타내고 # 2는 Array.prototype.push.apply를 나타냅니다. 솔리드 배열이 아닌 희소 배열에 대한 메소드를 테스트한다는 점만 다른 유사한 JSperf로 이것을 테스트 해 보겠습니다. 여기서 바로 찾을 수 있습니다 .

따라서이 특정 사용 사례의 성능 미래는 Array.prototype.push가 아니라 Array.prototype.concat에 있다고 생각합니다.

𝗖𝗹𝗮𝗿𝗶𝗳𝗶𝗰𝗮𝘁𝗶𝗼𝗻𝘀

𝗦𝗽𝗮𝗿𝗲 𝗔𝗿𝗿𝗮𝘆𝘀

배열의 특정 구성원이 단순히 누락 된 경우 예를 들면 다음과 같습니다.

// This is just as an example. In actual code, 
// do not mix different types like this.
var mySparseArray = [];
mySparseArray[0] = "foo";
mySparseArray[10] = undefined;
mySparseArray[11] = {};
mySparseArray[12] =  10;
mySparseArray[17] = "bar";
console.log("Length:   ", mySparseArray.length);
console.log("0 in it:  ", 0 in mySparseArray);
console.log("arr[0]:   ", mySparseArray[0]);
console.log("10 in it: ", 10 in mySparseArray);
console.log("arr[10]   ", mySparseArray[10]);
console.log("20 in it: ", 20 in mySparseArray);
console.log("arr[20]:  ", mySparseArray[20]);

또는 자바 스크립트를 사용하면 예비 배열을 쉽게 초기화 할 수 있습니다.

var mySparseArray = ["foo",,,,,,,,,,undefined,{},10,,,,,"bar"];

𝗔𝗿𝗿𝗮𝘆-𝗟𝗶𝗸𝗲𝘀

배열과 같은 length속성 은 최소한 속성이 있지만 new Array또는로 초기화되지 않은 객체입니다 []. 예를 들어, 아래의 객체는 배열 형으로 분류됩니다.

{0 : "foo", 1 : "bar", 길이 : 2}
document.body.children
새로운 Uint8Array (3)
  • 배열과 비슷하지만 배열로 강제 변환하면 생성자가 변경되기 때문에 배열과 비슷합니다.
(function () {반환 인수}) ()

배열과 같은 배열을 슬라이스와 같은 배열로 강제 변환하는 방법을 사용하여 어떤 일이 발생하는지 관찰하십시오.

  • 참고 : 성능 때문에 함수 인수에서 슬라이스를 호출하는 것은 좋지 않습니다.

배열과 같은 배열을 concat과 같은 배열로 강제 하지 않는 방법을 사용하여 발생하는 일을 관찰하십시오 .


9

JavaScript ES6을 사용하면 ... 연산자를 기본적으로 값으로 변환하는 스프레드 연산자로 사용할 수 있습니다. 그런 다음 다음과 같이 할 수 있습니다.

const myArray = [1,2,3,4,5];
const moreData = [6,7,8,9,10];

const newArray = [
  ...myArray,
  ...moreData,
];

구문이 간결하지만, 이것이 내부적으로 어떻게 작동하고 성능이 큰 배열에 미치는 영향을 모르겠습니다.


2
babel이 어떻게 변환하는지 살펴보면 Array.push.apply기술을 사용 하는 것보다 느리지 않아야한다는 것을 알 수 있습니다 .
emil.c

1
@ JackGiffin 나는 Ryan이 내부적으로 어떻게 작동하는지, 성능에 어떤 영향을 미치는지 모른다고 언급 한 것을 언급하고 있었지만 실제로이 접근법을 제안하지는 않았습니다. 어쨌든, 당신은 당신의 대답, 훌륭한 연구에 아주 좋은 일을 해왔으며, 그러한 세부 사항을 아는 것이 항상 좋습니다.
emil.c

9

여기 ES6 방법이 있습니다

var newArray = [];
let dataArray1 = [1,2,3,4]
let dataArray2 = [5,6,7,8]
newArray = [...dataArray1, ...dataArray2]
console.log(newArray)

위의 방법은 대부분의 경우에 적합하며 concat배열에 수십만 개의 항목이있는 것처럼 고려하지 않는 경우를 고려하십시오 .

    let dataArray1 = [1,2,3,4]
    let dataArray2 = [5,6,7,8]
    let newArray = dataArray1.concat(dataArray2);
    console.log(newArray)


8

Array.prototype.push.apply 에 대해 여러 가지 답변이 있습니다 . 다음은 분명한 예입니다.

var dataArray1 = [1, 2];
var dataArray2 = [3, 4, 5];
var newArray = [ ];
Array.prototype.push.apply(newArray, dataArray1); // newArray = [1, 2]
Array.prototype.push.apply(newArray, dataArray2); // newArray = [1, 2, 3, 4, 5]
console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5]

ES6 구문이있는 경우 :

var dataArray1 = [1, 2];
var dataArray2 = [3, 4, 5];
var newArray = [ ];
newArray.push(...dataArray1); // newArray = [1, 2]
newArray.push(...dataArray2); // newArray = [1, 2, 3, 4, 5]
console.log(JSON.stringify(newArray)); // Outputs: [1, 2, 3, 4, 5]


4

원래 배열을 수정하려면 다음을 펼치고 누를 수 있습니다.

var source = [1, 2, 3];
var range = [5, 6, 7];
var length = source.push(...range);

console.log(source); // [ 1, 2, 3, 5, 6, 7 ]
console.log(length); // 6

같은 유형의 항목 만 source배열 에 포함 시키려면 (예를 들어 숫자와 문자열을 혼합하지 않음) TypeScript를 사용하십시오.

/**
 * Adds the items of the specified range array to the end of the source array.
 * Use this function to make sure only items of the same type go in the source array.
 */
function addRange<T>(source: T[], range: T[]) {
    source.push(...range);
}

2

두 개의 배열 a와 b가 있습니다. 여기서 수행 한 코드는 배열 a 값이 배열 b로 푸시됩니다.

let a = [2, 4, 6, 8, 9, 15]

function transform(a) {
    let b = ['4', '16', '64']
    a.forEach(function(e) {
        b.push(e.toString());
    });
    return b;
}

transform(a)

[ '4', '16', '64', '2', '4', '6', '8', '9', '15' ]

1
답변으로 코드를 게시하지 마십시오. 코드가하는 일과 문제를 해결하는 방법을 설명하십시오.
Patrick Hund

0

이 시도:

var arrayA = [1, 2];
var arrayB = [3, 4];
var newArray = arrayB.reduce((pre, cur) => [...pre, ...cur], arrayA);
console.log(newArray)

-2

push () 함수 대신 IE에 concat 함수를 사용하십시오. 예,

var a=a.concat(a,new Array('amin'));

1
둘 다 IE와 매우 호환됩니다
Jack Giffin

-3

Тhis는 작동 코드이며 정상적으로 작동합니다.

var els = document.getElementsByTagName('input'), i;
var invnum = new Array();
var k = els.length;
for(i = 0; i < k; i++){invnum.push(new Array(els[i].id,els[i].value))}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.