development

새 배열을 만들지 않고 기존 JavaScript 배열을 다른 배열로 확장하는 방법

big-blog 2020. 9. 28. 09:33
반응형

새 배열을 만들지 않고 기존 JavaScript 배열을 다른 배열로 확장하는 방법


기존 자바 스크립트 배열을 다른 배열로 확장하는 방법, 즉 Python의 extend메서드 를 에뮬레이트하는 방법이없는 것 같습니다 .

다음을 달성하고 싶습니다.

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
>>> a
[1, 2, 3, 4, 5]

a.concat(b)메서드 가 있다는 것을 알고 있지만 단순히 첫 번째 배열을 확장하는 대신 새 배열을 만듭니다. (즉, 복사하지 않는 a것)보다 훨씬 클 때 효율적으로 작동하는 알고리즘을 원합니다 .ba

참고 : 이것은 배열에 무언가를 추가하는 방법 의 중복아닙니다 . -여기서 목표는 한 배열의 전체 내용을 다른 배열에 추가하고이를 "제자리에서"수행하는 것입니다. 즉, 확장 배열의 모든 요소를 ​​복사하지 않습니다.


.push메서드는 여러 인수를 사용할 수 있습니다. 스프레드 연산자사용하여 두 번째 배열의 모든 요소를 ​​인수로 전달할 수 있습니다 .push.

>>> a.push(...b)

브라우저가 ECMAScript 6을 지원하지 않는 경우 다음을 .apply대신 사용할 수 있습니다 .

>>> a.push.apply(a, b)

또는 더 명확하다고 생각하는 경우 :

>>> Array.prototype.push.apply(a,b)

배열 b이 너무 길면 이러한 모든 솔루션이 스택 오버플로 오류와 함께 실패합니다 (문제는 브라우저에 따라 약 100,000 개 요소에서 시작됨). b충분히 짧은 것을 보장 할 수없는 경우 다른 답변에 설명 된 표준 루프 기반 기술을 사용해야합니다.


업데이트 2018 : 더 나은 대답은 내 새로운 하나입니다 : a.push(...b). 이 질문에 실제로 답변 한 적이 없으므로 더 이상 찬성하지 마세요.하지만 2015 년 Google에서 처음으로 히트 한 해킹이었습니다. :)


단순히 "JavaScript array extend"를 검색하고 여기에 도착한 경우 Array.concat.

var a = [1, 2, 3];
a = a.concat([5, 4, 3]);

Concat은 스레드 스타터가 원하지 않았기 때문에 새 배열의 복사본을 반환합니다. 그러나 당신은 신경 쓰지 않을 수도 있습니다 (확실히 대부분의 용도에서 이것은 괜찮습니다).


스프레드 연산자의 형태로 이에 대한 멋진 ECMAScript 6 설탕도 있습니다.

const a = [1, 2, 3];
const b = [...a, 5, 4, 3];

(또한 복사합니다.)


루프 기반 기술을 사용해야합니다. 사용을 기반으로하는이 페이지의 다른 답변 .apply은 대형 어레이의 경우 실패 할 수 있습니다.

상당히 간결한 루프 기반 구현은 다음과 같습니다.

Array.prototype.extend = function (other_array) {
    /* You should include a test to check whether other_array really is an array */
    other_array.forEach(function(v) {this.push(v)}, this);
}

그런 다음 다음을 수행 할 수 있습니다.

var a = [1,2,3];
var b = [5,4,3];
a.extend(b);

DzinX의 답변 (push.apply 사용) 및 기타 .apply기반 방법은 우리가 추가하는 배열이 클 때 실패합니다 (테스트 결과 Chrome에서는 약 150,000 항목, Firefox에서는 500,000 항목 이상임). 이 jsperf 에서 발생하는이 오류를 볼 수 있습니다 .

큰 배열을 두 번째 인수로 사용하여 'Function.prototype.apply'를 호출하면 호출 스택 크기를 초과하여 오류가 발생합니다. (MDN에는 Function.prototype.apply를 사용하여 호출 스택 크기를 초과하는 위험에 대한 참고 사항이 있습니다. "적용 및 내장 함수"섹션을 참조하십시오.)

이 페이지의 다른 답변과 속도를 비교하려면 이 jsperf를 확인하십시오 ( EaterOfCode 덕분에). 루프 기반 구현 Array.push.apply은를 사용하는 것과 속도가 비슷 하지만 Array.slice.apply.

흥미롭게도 추가하려는 배열이 희소 한 경우 forEach기반 방법은 희소성을 활용하고 .apply기반 방법 보다 성능이 뛰어납니다 . 직접 테스트하려면 이 jsperf를 확인 하십시오.

그건 그렇고, forEach 구현을 다음과 같이 추가로 단축하려는 유혹을받지 마십시오.

Array.prototype.extend = function (array) {
    array.forEach(this.push, this);
}

이것은 쓰레기 결과를 생성하기 때문입니다! 왜? 때문에 Array.prototype.forEach이 호출하는 함수에 세 가지 인수를 제공 - 다음은 다음과 같습니다 (element_value, element_index, 오기 source_array). forEach"forEach (this.push, this)"를 사용하면 모든 반복이 첫 번째 배열로 푸시됩니다 !


요즘 가장 우아한 느낌은 다음과 같습니다.

arr1.push(...arr2);

확산 연산자에 대한 MDN 문서 ES2015 (ES6)이 좋은 달콤한 방법을 언급한다 :

더 나은 추진

예 : push는 종종 기존 배열의 끝에 배열을 푸시하는 데 사용됩니다. ES5에서 이것은 종종 다음과 같이 수행됩니다.

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
// Append all items from arr2 onto arr1
Array.prototype.push.apply(arr1, arr2);

스프레드가있는 ES6에서는 다음과 같이됩니다.

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

참고 수행 arr2거대 호출 스택이 jcdude의 대답에 따라, 오버 플로우 때문에, (000 (100)에 대한 항목에서 보관) 할 수 있습니다.


First a few words about apply() in JavaScript to help understand why we use it:

The apply() method calls a function with a given this value, and arguments provided as an array.

Push expects a list of items to add to the array. The apply() method, however, takes the expected arguments for the function call as an array. This allows us to easily push the elements of one array into another array with the builtin push() method.

Imagine you have these arrays:

var a = [1, 2, 3, 4];
var b = [5, 6, 7];

and simply do this:

Array.prototype.push.apply(a, b);

The result will be:

a = [1, 2, 3, 4, 5, 6, 7];

The same thing can be done in ES6 using the spread operator ("...") like this:

a.push(...b); //a = [1, 2, 3, 4, 5, 6, 7]; 

Shorter and better but not fully supported in all browsers at the moment.

Also if you want to move everything from array b to a, emptying b in the process, you can do this:

while(b.length) {
  a.push(b.shift());
} 

and the result will be as follows:

a = [1, 2, 3, 4, 5, 6, 7];
b = [];

If you want to use jQuery, there is $.merge()

Example:

a = [1, 2];
b = [3, 4, 5];
$.merge(a,b);

Result: a = [1, 2, 3, 4, 5]


I like the a.push.apply(a, b) method described above, and if you want you can always create a library function like this:

Array.prototype.append = function(array)
{
    this.push.apply(this, array)
}

and use it like this

a = [1,2]
b = [3,4]

a.append(b)

It is possible to do it using splice():

b.unshift(b.length)
b.unshift(a.length)
Array.prototype.splice.apply(a,b) 
b.shift() // Restore b
b.shift() // 

But despite being uglier it is not faster than push.apply, at least not in Firefox 3.0.


This solution works for me (using the spread operator of ECMAScript 6):

let array = ['my', 'solution', 'works'];
let newArray = [];
let newArray2 = [];
newArray.push(...array); // Adding to same array
newArray2.push([...array]); // Adding as child/leaf/sub-array
console.log(newArray);
console.log(newArray2);


You can create a polyfill for extend as I have below. It will add to the array; in-place and return itself, so that you can chain other methods.

if (Array.prototype.extend === undefined) {
  Array.prototype.extend = function(other) {
    this.push.apply(this, arguments.length > 1 ? arguments : other);
    return this;
  };
}

function print() {
  document.body.innerHTML += [].map.call(arguments, function(item) {
    return typeof item === 'object' ? JSON.stringify(item) : item;
  }).join(' ') + '\n';
}
document.body.innerHTML = '';

var a = [1, 2, 3];
var b = [4, 5, 6];

print('Concat');
print('(1)', a.concat(b));
print('(2)', a.concat(b));
print('(3)', a.concat(4, 5, 6));

print('\nExtend');
print('(1)', a.extend(b));
print('(2)', a.extend(b));
print('(3)', a.extend(4, 5, 6));
body {
  font-family: monospace;
  white-space: pre;
}


Combining the answers...

Array.prototype.extend = function(array) {
    if (array.length < 150000) {
        this.push.apply(this, array)
    } else {
        for (var i = 0, len = array.length; i < len; ++i) {
            this.push(array[i]);
        };
    }  
}

Another solution to merge more than two arrays

var a = [1, 2],
    b = [3, 4, 5],
    c = [6, 7];

// Merge the contents of multiple arrays together into the first array
var mergeArrays = function() {
 var i, len = arguments.length;
 if (len > 1) {
  for (i = 1; i < len; i++) {
    arguments[0].push.apply(arguments[0], arguments[i]);
  }
 }
};

Then call and print as:

mergeArrays(a, b, c);
console.log(a)

Output will be: Array [1, 2, 3, 4, 5, 6, 7]


The answer is super simple.

>>> a = [1, 2]
[1, 2]
>>> b = [3, 4, 5]
[3, 4, 5]
>>> SOMETHING HERE
(The following code will combine the two arrays.)

a = a.concat(b);

>>> a
[1, 2, 3, 4, 5]

Concat acts very similarly to JavaScript string concatenation. It will return a combination of the parameter you put into the concat function on the end of the array you call the function on. The crux is that you have to assign the returned value to a variable or it gets lost. So for example

a.concat(b);  <--- This does absolutely nothing since it is just returning the combined arrays, but it doesn't do anything with it.

Use Array.extend instead of Array.push for > 150,000 records.

if (!Array.prototype.extend) {
  Array.prototype.extend = function(arr) {
    if (!Array.isArray(arr)) {
      return this;
    }

    for (let record of arr) {
      this.push(record);
    }

    return this;
  };
}

Super simple, does not count on spread operators or apply, if that's an issue.

b.map(x => a.push(x));

After running some performance tests on this, it's terribly slow, but answers the question in regards to not creating a new array. Concat is significantly faster, even jQuery's $.merge() whoops it.

https://jsperf.com/merge-arrays19b/1

참고URL : https://stackoverflow.com/questions/1374126/how-to-extend-an-existing-javascript-array-with-another-array-without-creating

반응형