배열에 값을 추가하는 가장 효율적인 방법


268

크기가 N(where N > 0) 인 배열이 있다고 가정하면 O (N + 1) 단계가 필요하지 않은 배열 앞에 더 효율적인 방법이 있습니까?

코드에서 본질적으로 현재하고있는 것은

function prependArray(value, oldArray) {
  var newArray = new Array(value);

  for(var i = 0; i < oldArray.length; ++i) {
    newArray.push(oldArray[i]);
  }

  return newArray;
}

링크 된 목록과 포인터를 좋아하는만큼 네이티브 JS 데이터 형식을 사용하여보다 효과적인 방법이 필요하다고 생각합니다.
samccone

@ samccone : 그래 내 의견을 무시 무시 죄송합니다, 당신이 자바라고 생각 : P
GWW

3
Java, JavaScript, C 또는 Python의 경우 언어가 중요하지 않습니다. 배열과 연결된 목록 간의 복잡성 균형은 동일합니다. 자바와 달리 내장 클래스가 없기 때문에 JS에서 링크 된 목록은 다루기 어려울 수 있지만 실제로 원하는 것이 O (1) 삽입 시간이면 링크 된 목록을 원합니다.
mgiuca

1
복제해야합니까?
Ryan Florence

1
복제가 필요한 경우 unshift는 부적절합니다. 원래 배열을 변경하고 사본을 만들지 않기 때문입니다.
mgiuca

답변:


492

big-O 측면에서 더 효율적인지 확실하지 않지만 unshift방법을 사용하는 것이 더 간결합니다.

var a = [1, 2, 3, 4];
a.unshift(0);
a; // => [0, 1, 2, 3, 4]

[편집하다]

jsPerf 벤치 마크 는 어레이를 제자리에서 수정해도 괜찮다 unshift 다른 big-O 성능에 관계없이 적어도 몇 개의 브라우저에서 상당히 빠르다 는 것을 보여줍니다 . 원래 배열을 변경할 수 없다면 아래 스 니펫과 같은 작업을 수행 할 수 있습니다. 솔루션보다 훨씬 빠르지 않은 것 같습니다.

a.slice().unshift(0); // Use "slice" to avoid mutating "a".

[편집 2]

완전성 prependArray(...)을 위해 OP의 예제 대신 다음 함수를 사용 하여 Array unshift(...)메소드를 활용할 수 있습니다 .

function prepend(value, array) {
  var newArray = array.slice();
  newArray.unshift(value);
  return newArray;
}

var x = [1, 2, 3];
var y = prepend(0, x);
y; // => [0, 1, 2, 3];
x; // => [1, 2, 3];

190
prepend" unshift" 에게 전화하기로 결정한 사람은 누구 입니까?
Scott Stafford

12
@ScottStafford unshift는 이러한 배열 작업에 더 적절하게 들립니다 (요소를 물리적으로 이동시킵니다). 문자 그대로 요소를 추가 prepend하는 링크 된 목록에 더 적합합니다 .
CamilB

12
unshift는 이동하는 보완 기능입니다. "선두"라고 부르는 것이 이상한 선택입니다. 언 시프트는 푸시가 터지면서 쉬프트하는 것입니다.
Sir Robert

9
이 솔루션에는 한 가지 문제 만 있습니다. unshift () 는이 답변에서 와 같이 배열 이 아닌 length를 반환 하지 않습니까? w3schools.com/jsref/jsref_unshift.asp
iDVB

4
push그리고 unshift모두 포함하는 u반면, pop그리고 shift필요가 없습니다.
Qian Chen

70

ES6에서는 이제 스프레드 연산자 를 사용하여 새 요소를 원래 요소 앞에 삽입하여 새 배열을 만들 수 있습니다.

// Prepend a single item.
const a = [1, 2, 3];
console.log([0, ...a]);

// Prepend an array.
const a = [2, 3];
const b = [0, 1];
console.log([...b, ...a]);

2018-08-17 업데이트 : 성능

나는이 대답이 더 기억하기 쉽고 간결한 대안 구문을 제시하기 위해 의도했습니다. 일부 벤치 마크 ( 이 다른 답변 참조 )에 따르면이 구문은 상당히 느립니다. 루프에서 이러한 많은 작업을 수행하지 않는 한 이것은 중요하지 않을 것입니다.


4
2017 년 기준으로 투표해야합니다. 간결합니다. 스프레드를 사용하면 새로운 스트림을 제공하여 추가 수정을 연결하는 데 유용 할 수 있습니다. 그것은 또한 순수합니다 (a와 b는 영향을받지 않습니다)
Simon

당신은에 비해 소요되는 시간 있습니다 ABT 언급 didnt는unshift
Shashank 비벡

@ShashankVivek에게 감사합니다. 나는이 대답이 더 기억하기 쉽고 간결한 대안 구문을 제시하기 위해 의도했습니다. 업데이트하겠습니다.
Frank Tan

@FrankTan : 건배 :) +1
Shashank Vivek

46

다른 배열 앞에 배열을 추가하는 경우을 사용하는 것이 더 효율적 concat입니다. 그래서:

var newArray = values.concat(oldArray);

그러나 이것은 oldArray 크기에서 여전히 O (N)입니다. 여전히 oldArray를 수동으로 반복하는 것보다 효율적입니다. 또한 세부 정보에 따라 많은 값을 앞에 추가하려는 경우 각 값을 개별적으로 추가하는 대신 배열에 먼저 배치 한 다음 끝에 oldArray를 연결하는 것이 좋습니다.

배열은 첫 번째 요소가 고정 된 위치에있는 연속 메모리에 저장되므로 oldArray 크기에서 O (N)보다 더 나은 방법은 없습니다. 첫 번째 요소 앞에 삽입하려면 다른 모든 요소를 ​​이동해야합니다. 이 문제를 해결할 방법이 필요하면 @GWW가 말한 것을 수행하고 연결된 목록 또는 다른 데이터 구조를 사용하십시오.


2
네, 잊어 버렸습니다 unshift. 그러나 a) oldArray를 변경하는 반면 concat그렇지 않은 경우 (상황에 따라 어떤 것이 더 낫습니까) b) 하나의 요소 만 삽입합니다.
mgiuca

1
와우, 그것은 훨씬 느리다. 글쎄, 내가 말했듯이, 그것은 배열의 사본을 만들고 (또한 새로운 배열을 생성하는 [0]) unshift는 그것을 제자리로 돌리고 있습니다. 그러나 둘 다 O (N)이어야합니다. 또한 해당 사이트에 대한 링크를 응원합니다. 매우 편리합니다.
mgiuca

2
concat은 배열을 반환하고 unshift는 새로운 길이
Z를

32

배열 (a1에 배열 a2)을 추가하려면 다음을 사용할 수 있습니다.

var a1 = [1, 2];
var a2 = [3, 4];
Array.prototype.unshift.apply(a1, a2);
console.log(a1);
// => [3, 4, 1, 2]

6

f 이전 배열을 유지하고 이전 배열을 슬라이스하고 새 값을 슬라이스의 시작 부분으로 이동하지 않아야합니다.

var oldA=[4,5,6];
newA=oldA.slice(0);
newA.unshift(1,2,3)

oldA+'\n'+newA

/*  returned value:
4,5,6
1,2,3,4,5,6
*/

4

나는 여러 가지 다른 방법에 대한 새로운 테스트를 받았습니다. 소형 어레이 (<1000 elem)의 경우 리더는 푸시 방식과 결합 된 사이클을위한 것입니다. 거대한 배열의 경우 Unshift 방법이 리더가됩니다.

그러나이 상황은 Chrome 브라우저에만 해당됩니다. Firefox에서 unshift는 뛰어난 최적화 기능을 갖추고 있으며 모든 경우에 더 빠릅니다.

ES6 스프레드는 모든 브라우저에서 100 배 이상 느립니다.

https://jsbench.me/cgjfc79bgx/1


좋은 답변입니다! 그러나 일부를 잃지 않도록 jsbench가 사라지는 경우와 같이 테스트 사례를 여기에 재현 할 수 있습니다 (일부 샘플 실행 결과가있을 수 있음).
ruffin

3

특별한 방법이 있습니다 :

a.unshift(value);

그러나 배열에 여러 요소를 추가하려면 그러한 방법을 사용하는 것이 더 빠릅니다.

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

function prependArray(a, b) {
    var args = b;
    args.unshift(0);
    args.unshift(0);
    Array.prototype.splice.apply(a, args);
}

prependArray(a, b);
console.log(a); // -> [4, 5, 1, 2, 3]

2
아니요 ... unshift는 배열을 첫 번째 인수로 추가합니다. var a = [4, 5]; a. 변이 ([1,2,3]); console.log (a); //-> [[4, 5], 1, 2, 3]
bjornd

4
당신이 올바른지! 당신이 사용해야 할 것Array.prototype.unshift.apply(a,b);
david

1

적절한 위치에 추가하는 예 :

var A = [7,8,9]
var B = [1,2,3]

A.unshift(...B)

console.log(A) // [1,2,3,7,8,9]


1

호출 unshift하면 새 배열의 길이 만 반환됩니다. 따라서 처음에 요소를 추가하고 새 배열을 반환하려면 다음과 같이하십시오.

let newVal = 'someValue';
let array = ['hello', 'world'];
[ newVal ].concat(array);

또는 간단히 스프레드 연산자를 사용하십시오.

[ newVal, ...array ]

이렇게하면 원래 배열은 그대로 유지됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.