채워지지 않은 JavaScript 배열을 만드는 가장 효율적인 방법은 무엇입니까?


602

JavaScript에서 임의의 길이 0으로 채워진 배열을 만드는 가장 효율적인 방법은 무엇입니까?


7
이것에 대한 실제 데이터 : jsperf.com/zeroarrayjs
Web_Designer

7
ES6 채우기 는 기본적 으로이 작업을 수행 할 수 있습니다.
살바도르 달리

1
arr = new Array (길이 +1) .joint (character) .split ( '');
Jordan Stefanelli

4
업데이트 2016 : 또 다른 사용자 정의 벤치 마크 : jsfiddle.net/basickarl/md5z0Lqq
K-SO의 독성이 증가하고 있습니다.

1
let i = 0; Array.from(Array(10), ()=>i++);
Bart Hoekstra

답변:


543

ES6가 소개 Array.prototype.fill합니다. 다음과 같이 사용할 수 있습니다 :

new Array(len).fill(0);

그것이 빠르면 확실하지 않지만 짧고 자체 설명하기 때문에 좋아합니다.

여전히 IE 에는 없지만 ( 호환성 검사 ) polyfill을 사용할 수 있습니다 .


15
채우기가 빠릅니다. new Array(len)고통스럽게 느립니다. (arr = []).length = len; arr.fill(0);가장 빠른 솔루션에 관한 어디서나 볼 ... 또는 적어도 묶여 필자
포주 Trizkit

7
@PimpTrizkit는 arr = Array(n)(arr = []).length = n사양에 따라 동일하게 동작합니다. 일부 구현에서는 더 빠를 수 있지만 큰 차이는 없다고 생각합니다.
Oriol

2
글쎄, 나는 다차원 배열로 테스트를 시작했으며 테스트 케이스의 속도를 크게 향상시키는 것처럼 보였습니다. FF41 및 Chrome45.0.2454.99 m에서 더 많은 테스트를 마쳤습니다. 예, 제 자신을 설명 할 공간이 더 필요하다고 생각합니다. 내 테스트의 대부분은 내가 받아 들일 편견이었다. 그러나 이것을 확인하십시오. var를 미리 정의하고 Chrome과 FF 모두에서 속도 테스트 (arr = []).length = 1000; 에 대해이 줄 을 사용하면 arr = new Array(1000);... new매우 느립니다. 이제 배열 길이가 더 작은 경우 <50 또는 약 50 정도가 new Array()더 좋습니다.
Pimp Trizkit

4
... 나는이 부분을 놓쳤다는 것을 인정할 것입니다 ... 테스트에 두 번째 줄을 추가하면 arr.fill(0) ... 모든 것이 변합니다. 이제 new Array()배열 크기> 100000에 도달 할 때를 제외하고 대부분의 경우 사용 이 더 빠릅니다. 그러면 속도가 다시 증가하는 것을 볼 수 있습니다. 그러나 실제로 0으로 미리 채울 필요가 없으며 빈 배열의 표준 falisy를 사용할 수 있습니다. 그렇다면 (arr = []).length = x대부분의 경우 테스트 사례에서 미치게 빠릅니다.
Pimp Trizkit

4
배열 (예 : map 또는 forEach)을 반복하려면 값 을 설정해야합니다 . 그렇지 않으면 해당 인덱스를 건너 뜁니다. 설정 한 값은 원하는대로 지정할 수 있으며 정의되지 않은 경우도 있습니다. 예 : 시도 new Array(5).forEach(val => console.log('hi'));new Array(5).fill(undefined).forEach(val => console.log('hi'));.
ArneHugo 2016 년

387

이것은 오래된 실이지만 2 센트를 더하고 싶었습니다. 이것이 얼마나 느리거나 빠른지 잘 모르겠지만 빠른 라이너입니다. 여기 내가하는 일이 있습니다.

숫자로 미리 채우려면 :

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
// [0, 0, 0, 0, 0]

문자열로 미리 채우려면 :

Array.apply(null, Array(3)).map(String.prototype.valueOf,"hi")
// ["hi", "hi", "hi"]

다른 답변은 다음과 같이 제안했습니다.

new Array(5+1).join('0').split('')
// ["0", "0", "0", "0", "0"]

그러나 "0"이 아닌 0 (숫자) (문자열 내부의 0)을 원하면 다음을 수행 할 수 있습니다.

new Array(5+1).join('0').split('').map(parseFloat)
// [0, 0, 0, 0, 0]

6
좋은 답변입니다! 트릭을 설명해 주 Array.apply(null, new Array(5)).map(...)시겠습니까? 스펙이 알려주는 것처럼 단순히 (new Array (5)). map (...)하는 것은 작동하지 않습니다
Dmitry Pashkevich

36
(btw, 우리는 정말로 필요하지 않습니다. new) Array(5)당신이 다음과 같은 객체를 만들 때 : { length: 5, __proto__: Array.prototype }-try console.dir( Array(5) ). 주의 사항은 어떤 속성을 가지고 있지 않음을 0, 1, 2, 등하지만 당신을 때 apply에게 있음을 Array생성자, 그것은 말처럼 Array(undefined, undefined, undefined, undefined, undefined). 그리고 당신은 좀 비슷한 객체를 얻습니다 { length: 5, 0: undefined, 1: undefined...}. map속성에서 작동 0, 1등을하는 당신의 예를 들어 일을하지 않는 이유는,하지만 당신은 사용하는 경우 apply는 않습니다.
zertosh

4
에 대한 첫 번째 매개 변수 .apply는 실제로 원하는 this것입니다. 이러한 목적을 위해 this중요하지 않습니다 – 우리는 "기능"을 퍼뜨리는 매개 변수에만 관심이 .apply있기 때문에 어떤 값이든 될 수 있습니다. 나는 null그것이 싸기 때문에 좋아 합니다. 아마도 사용하고 싶지 {}않거나 []아무 이유없이 객체를 인스턴스화했기 때문입니다.
zertosh

2
또한 크기 + 초기화로 초기화하는 것이 푸시보다 훨씬 빠릅니다. 테스트 사례 참조 jsperf.com/zero-fill-2d-array
Colin

2
Array.apply (null, Array (5)). map (x => 0)은 어떻습니까? 조금 더 짧습니다!
아치 리눅스 Tux

97

사전 계산 된 값으로 배열을 채우는 우아한 방법

지금까지 아무도 언급하지 않은 ES6을 사용하여 수행하는 또 다른 방법은 다음과 같습니다.

> Array.from(Array(3), () => 0)
< [0, 0, 0]

지도 함수를의 두 번째 매개 변수로 전달하여 작동합니다 Array.from.

위의 예에서 첫 번째 매개 변수는 값으로 채워진 3 개의 위치로 구성된 배열을 할당 한 undefined다음 람다 함수가 이들 각각을 값에 매핑합니다 0.

Array(len).fill(0)더 짧지 만 계산을 먼저 수행하여 배열을 채워야하는 경우 작동하지 않습니다 (질문은 요청하지 않았지만 많은 사람들이 여기를 찾습니다) .

예를 들어 10 개의 난수를 가진 배열이 필요한 경우 :

> Array.from(Array(10), () => Math.floor(10 * Math.random()))
< [3, 6, 8, 1, 9, 3, 0, 6, 7, 1]

동등한 것보다 더 간결하고 우아합니다.

const numbers = Array(10);
for (let i = 0; i < numbers.length; i++) {
    numbers[i] = Math.round(10 * Math.random());
}

이 메소드는 콜백에 제공된 인덱스 매개 변수를 활용하여 일련의 숫자를 생성하는 데에도 사용할 수 있습니다.

> Array.from(Array(10), (d, i) => i)
< [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

보너스 답변 : 문자열을 사용하여 배열을 채우십시오 repeat()

이 답변은 많은 관심을 받고 있기 때문에이 멋진 트릭을 보여주고 싶었습니다. 내 주요 대답만큼 유용하지는 않지만 여전히 알려지지 않았지만 매우 유용한 String repeat()메서드를 소개합니다. 요령은 다음과 같습니다.

> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]

시원 해요? repeat()원래 문자열을 특정 횟수만큼 반복하는 문자열을 만드는 데 유용한 방법입니다. 그 후 split()우리를 위해 배열을 만든 다음 map()원하는 값으로 ping합니다. 단계별로 분류 :

> "?".repeat(10)
< "??????????"

> "?".repeat(10).split("")
< ["?", "?", "?", "?", "?", "?", "?", "?", "?", "?"]

> "?".repeat(10).split("").map(() => Math.floor(10 * Math.random()))
< [5, 6, 3, 5, 0, 8, 2, 7, 4, 1]

:) 생산 코드에 도달 할 해당 게시물의 응접실 트릭 많은, 그러나 희망 없음
에릭 그레인

하지만 repeat트릭은 확실히 생산에 원하지 않는, Array.from():-) 완벽하게 괜찮
루시오 PAIVA

실제로 Array.from ()은 기본적으로 배열을 만들고 map ()으로 반복하여 각 항목에서 함수를 호출하여 새 배열을 만든 다음 첫 번째 배열을 버립니다 ... 작은 배열의 경우 다음과 같습니다. 무해한는 더 큰 배열의 경우,이 패턴의 종류입니다 "메모리 돼지": 브라우저를 호출하는 사람들의 결과
에릭 그레인을

큰 배열을 다루는 사람들은 이것보다 더 잘 알아야합니다. 그러나 일반적인 응용 프로그램의 경우 즉시 폐기 할 일반 크기의 보조 배열 (최대 10k 요소)을 만드는 것은 완벽합니다 (최신 Chrome으로 테스트 된 추가 배열 생성을 피하는 것과 같은 시간이 걸립니다). 그런 경우, 작은 성능 최적화보다 가독성이 중요해집니다. O (n) 시간에 대해서는 각 요소 (내 대답의 주요 주제)에 대해 다른 것을 계산 해야하는 경우 필요합니다. 이 토론은 매우 흥미 롭습니다. 제기 해 주셔서 감사합니다!
Lucio Paiva

88

한마디로

가장 빠른 솔루션

let a = new Array(n); for (let i=0; i<n; ++i) a[i] = 0;

가장 짧은 (핸디) 솔루션

Array(n).fill(0)


세부

오늘 2020.06.09 Chrome 83.0, Firefox 77.0 및 Safari 13.1 브라우저에서 macOS High Sierra 10.13.6에서 테스트를 수행합니다. 두 가지 테스트 사례에 대해 선택한 솔루션을 테스트합니다.

  • 10 개의 요소가있는 작은 배열- 여기에서 테스트를 수행 할 수 있습니다
  • 1M 요소의 큰 배열- 여기에서 테스트를 수행 할 수 있습니다

결론

  • new Array(n)+for(N) 기반 솔루션은 소형 어레이 및 대형 어레이에 가장 빠른 솔루션이며 (Chrome 제외하지만 여전히 빠름) 빠른 크로스 브라우저 솔루션으로 권장됩니다.
  • new Float32Array(n)(I) 기반 솔루션 은 비 전형적인 배열을 반환 push(..)하므로 (예를 들어 호출 할 수 없음 ) 결과를 다른 솔루션과 비교할 수는 없지만이 솔루션은 모든 브라우저에서 큰 배열의 다른 솔루션보다 약 10-20 배 빠릅니다.
  • for(L, M, N, O) 기반 솔루션 은 소형 어레이에 빠릅니다.
  • fill(B, C) 기반 솔루션 은 Chrome 및 Safari에서 빠르지 만 큰 배열의 경우 Firefox에서 가장 느립니다. 그들은 작은 배열에 대해 중간 속도입니다
  • Array.apply(P) 기반 솔루션 은 큰 배열에서 오류를 발생시킵니다.

여기에 이미지 설명을 입력하십시오

코드와 예제

아래 코드는 측정에 사용되는 솔루션을 나타냅니다.

Chrome의 결과 예

여기에 이미지 설명을 입력하십시오


Chrome 77에서 몇 가지 테스트를 실행했으며 push ()가있는 간단한 루프가 fill ()보다 두 배 빠릅니다 ... fill ()의 미묘한 부작용으로 인해보다 효율적인 구현을 방해하는 것은 무엇입니까?
Eric Grange

@EricGrange 나는 대답을 업데이트합니다-맨 아래에는 제안과 함께 benchamrk 링크를 업데이트하십시오 : case P- let a=[]; for(i=n;i--;) a.push(0);그러나 4 배 느립니다 fill(0).
Kamil Kiełczewski

2
좋은 측정. 분석 : 반복 할 때마다 배열의 크기가 조정되므로 G가 느리고 크기 조정은 새로운 메모리 할당을 의미합니다. 크기 조정이 한 번만 수행되므로 A, B, M이 빠릅니다. +1
롤랜드

이것은 실제로 질문에 대한 답변을 시도하는 몇 가지 답변 중 하나입니다. 불행히도 적어도 2020 년 6 월에있는 모든 브라우저에서의 대답이 아닌 대답을 고수하고 가장 빠른 실제 답변을 놓치면 실패합니다 a = new Array(n); for (let i = 0; i < n; ++i) a[i] = 0;. 테스트
gman

@gman 실제로 당신이 맞아요-어떻게 놓쳤는 지 이해할 수 없어요-새로운 테스트를 수행하고 자세한 내용으로 답변을 업데이트합니다-감사합니다 :)
Kamil Kiełczewski

63

이미 언급 한 ES 6 채우기 방법은이를 잘 처리합니다. 대부분의 최신 데스크탑 브라우저는 이미 현재 필요한 배열 프로토 타입 방법 (Chromium, FF, Edge 및 Safari)을 지원합니다 [ 1 ]. MDN에 대한 세부 정보를 찾을 수 있습니다 . 간단한 사용법 예는

a = new Array(10).fill(0);

현재 브라우저 지원이 제공되므로 사용자가 최신 데스크탑 브라우저를 사용하고 있는지 확신 할 수없는 경우이를 사용하는 것이 좋습니다.


4
참조 유형을 채우면 모든 유형에서 동일한 참조가됩니다. 새로운 어레이 (10) .fill (널) .MAP (() => [])이 (처음에 하하 저를 불)의 주위에 얻을 수있는 간결한 방법이 될 것입니다
존 Culviner

4
업데이트 2016 :이 방법은 물에서 다른 모든 것을 날려 버리고 벤치 마크를 보려면 여기를 클릭하십시오 : jsfiddle.net/basickarl/md5z0Lqq
K-SO의 독성이 증가하고 있습니다.

이것은 배열에서 작동합니다. a = Array(10).fill(null).map(() => { return []; });
Andy

2
@AndrewAnthonyGerst Terser :a = Array(10).fill(0).map( _ => [] );
Phrogz

50

참고 : 2013 년 8 월 추가, 2015 년 2 월 업데이트 : 2009 년 아래 답변은 JavaScript의 일반 Array유형과 관련이 있습니다. ES2015에 정의되어 있고 현재 많은 브라우저에서 사용 가능한 최신 유형의 배열 과 관련이 없습니다 Int32Array. 또한 ES2015은 추가 점에 유의 fill모두 방법을 배열 하고 입력 배열 을 채우기 위해 가장 효율적인 방법이 될 것입니다 ...

또한 배열을 만드는 방법에 따라 구현에 큰 차이가 생길 수 있습니다. 특히 Chrome의 V8 엔진은 가능한 경우 고효율의 연속 메모리 배열을 사용하여 필요할 때만 객체 기반 배열로 이동하려고 시도합니다.


대부분의 언어에서는 다음과 같이 사전 할당 된 후 0으로 채워집니다.

function newFilledArray(len, val) {
    var rv = new Array(len);
    while (--len >= 0) {
        rv[len] = val;
    }
    return rv;
}

그러나 JavaScript 배열 은 실제로 배열 이 아니며 다른 모든 JavaScript 객체와 마찬가지로 키 / 값 맵이므로 "할당"할 필요가 없습니다 (길이를 설정해도 많은 슬롯을 채울 수는 없습니다). 구현이 키 처리를 최적화했을 때 키를 역순으로 추가하여 0으로 카운트 다운하는 이점 (루프에서 비교를 빠르게하는 것)이 중요하지 않다고 믿을만한 이유가 있습니까? 이론적으로 배열과 관련하여 일반적으로 순서대로 수행합니다.

실제로 Matthew Crumley는 Firefox에서 카운트 다운이 카운트 업보다 카운트 다운이 현저히 느리다는 것을 지적했습니다. 결과는 확인할 수 있습니다. 배열의 일부입니다 (0에서 루핑하는 것이 var의 한계까지 루핑하는 것보다 여전히 빠릅니다). Firefox에서 요소를 역순으로 배열에 추가하는 것은 분명히 느린 작업입니다. 실제로 결과는 JavaScript 구현에 따라 상당히 다양합니다 (놀라운 것은 아닙니다). 다음은 브라우저 구현을위한 빠르고 더러운 테스트 페이지 (아래)입니다 (매우 더럽고 테스트 중에 생성되지 않으므로 최소한의 피드백 만 제공하며 스크립트 시간 제한을 무시 함). 테스트 사이에 새로 고침을 권장합니다. 그렇지 않으면 반복 테스트에서 FF (적어도)가 느려집니다.

Array # concat을 사용하는 상당히 복잡한 버전은 1,000에서 2,000 개의 요소 배열보다 FF에서 바로 초기화하는 것보다 빠릅니다. 그러나 Chrome의 V8 엔진에서는 straight init가 매번 승리합니다.

테스트 페이지는 다음과 같습니다 ( 라이브 사본 ).

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zero Init Test Page</title>
<style type='text/css'>
body {
    font-family:    sans-serif;
}
#log p {
    margin:     0;
    padding:    0;
}
.error {
    color:      red;
}
.winner {
    color:      green;
    font-weight:    bold;
}
</style>
<script type='text/javascript' src='prototype-1.6.0.3.js'></script>
<script type='text/javascript'>
var testdefs = {
    'downpre':  {
        total:  0,
        desc:   "Count down, pre-decrement",
        func:   makeWithCountDownPre
    },
    'downpost': {
        total:  0,
        desc:   "Count down, post-decrement",
        func:   makeWithCountDownPost
    },
    'up':       {
        total:  0,
        desc:   "Count up (normal)",
        func:   makeWithCountUp
    },
    'downandup':  {
        total:  0,
        desc:   "Count down (for loop) and up (for filling)",
        func:   makeWithCountDownArrayUp
    },
    'concat':   {
        total:  0,
        desc:   "Concat",
        func:   makeWithConcat
    }
};

document.observe('dom:loaded', function() {
    var markup, defname;

    markup = "";
    for (defname in testdefs) {
        markup +=
            "<div><input type='checkbox' id='chk_" + defname + "' checked>" +
            "<label for='chk_" + defname + "'>" + testdefs[defname].desc + "</label></div>";
    }
    $('checkboxes').update(markup);
    $('btnTest').observe('click', btnTestClick);
});

function epoch() {
    return (new Date()).getTime();
}

function btnTestClick() {

    // Clear log
    $('log').update('Testing...');

    // Show running
    $('btnTest').disabled = true;

    // Run after a pause while the browser updates display
    btnTestClickPart2.defer();
}
function btnTestClickPart2() {

    try {
        runTests();
    }
    catch (e) {
        log("Exception: " + e);
    }

    // Re-enable the button; we don't yheidl
    $('btnTest').disabled = false;
}

function runTests() {
    var start, time, counter, length, defname, def, results, a, invalid, lowest, s;

    // Get loops and length
    s = $F('txtLoops');
    runcount = parseInt(s);
    if (isNaN(runcount) || runcount <= 0) {
        log("Invalid loops value '" + s + "'");
        return;
    }
    s = $F('txtLength');
    length = parseInt(s);
    if (isNaN(length) || length <= 0) {
        log("Invalid length value '" + s + "'");
        return;
    }

    // Clear log
    $('log').update('');

    // Do it
    for (counter = 0; counter <= runcount; ++counter) {

        for (defname in testdefs) {
            def = testdefs[defname];
            if ($('chk_' + defname).checked) {
                start = epoch();
                a = def.func(length);
                time = epoch() - start;
                if (counter == 0) {
                    // Don't count (warm up), but do check the algorithm works
                    invalid = validateResult(a, length);
                    if (invalid) {
                        log("<span class='error'>FAILURE</span> with def " + defname + ": " + invalid);
                        return;
                    }
                }
                else {
                    // Count this one
                    log("#" + counter + ": " + def.desc + ": " + time + "ms");
                    def.total += time;
                }
            }
        }
    }

    for (defname in testdefs) {
        def = testdefs[defname];
        if ($('chk_' + defname).checked) {
            def.avg = def.total / runcount;
            if (typeof lowest != 'number' || lowest > def.avg) {
                lowest = def.avg;
            }
        }
    }

    results =
        "<p>Results:" +
        "<br>Length: " + length +
        "<br>Loops: " + runcount +
        "</p>";
    for (defname in testdefs) {
        def = testdefs[defname];
        if ($('chk_' + defname).checked) {
            results += "<p" + (lowest == def.avg ? " class='winner'" : "") + ">" + def.desc + ", average time: " + def.avg + "ms</p>";
        }
    }
    results += "<hr>";
    $('log').insert({top: results});
}

function validateResult(a, length) {
    var n;

    if (a.length != length) {
        return "Length is wrong";
    }
    for (n = length - 1; n >= 0; --n) {
        if (a[n] != 0) {
            return "Index " + n + " is not zero";
        }
    }
    return undefined;
}

function makeWithCountDownPre(len) {
    var a;

    a = new Array(len);
    while (--len >= 0) {
        a[len] = 0;
    }
    return a;
}

function makeWithCountDownPost(len) {
    var a;

    a = new Array(len);
    while (len-- > 0) {
        a[len] = 0;
    }
    return a;
}

function makeWithCountUp(len) {
    var a, i;

    a = new Array(len);
    for (i = 0; i < len; ++i) {
        a[i] = 0;
    }
    return a;
}

function makeWithCountDownArrayUp(len) {
    var a, i;

    a = new Array(len);
    i = 0;
    while (--len >= 0) {
        a[i++] = 0;
    }
    return a;
}

function makeWithConcat(len) {
    var a, rem, currlen;

    if (len == 0) {
        return [];
    }
    a = [0];
    currlen = 1;
    while (currlen < len) {
        rem = len - currlen;
        if (rem < currlen) {
            a = a.concat(a.slice(0, rem));
        }
        else {
            a = a.concat(a);
        }
        currlen = a.length;
    }
    return a;
}

function log(msg) {
    $('log').appendChild(new Element('p').update(msg));
}
</script>
</head>
<body><div>
<label for='txtLength'>Length:</label><input type='text' id='txtLength' value='10000'>
<br><label for='txtLoops'>Loops:</label><input type='text' id='txtLoops' value='10'>
<div id='checkboxes'></div>
<br><input type='button' id='btnTest' value='Test'>
<hr>
<div id='log'></div>
</div></body>
</html>

요소를 액세스하지 않고 (삭제하지 않고) 이미 사전 할당 한 경우 뒤로 채우기가 중요하다는 것을 확신하지 못합니다. 내가 잘못?
삼부작

뒤로 채우기의 요점은 특히 배열과 관련이 없으며 잠시 동안 이스케이프 조건과 관련이 있습니다. false 0은 루프를 매우 효율적으로 종료합니다
annakata

(방금이 코드가 실제로 그것을 사용하지 않는다는 것을
알았지 만

@annakata, 0은 유효한 인덱스이기 때문에 여기서 사용할 수 없습니다.
삼부작

@triptych : 사실이 아닙니다. 필요한 것은 올바른 순서입니다. – 내 게시물 참조
annakata

34

기본적으로 Uint8Array, Uint16Array그리고 Uint32Array클래스를 사용하면 복잡한 충전 기술을 필요가 없습니다, 단지 수행의 값으로 0을 유지 :

var ary = new Uint8Array(10);

배열의 모든 요소는 ary기본적으로 0입니다.


5
이것은 좋지만 일반 배열과 동일하게 취급 할 수는 없습니다 (예 : Array.isArray(ary)is) false. 길이는 읽기 전용이므로 다음과 같이 새 항목을 푸시 할 수 없습니다ary.push
MusikAnimal

입력 된 모든 배열을 0기본 값으로 유지 합니다.
jfunk

2
@MusikAnimal Array.from(new Uint8Array(10))은 일반 배열을 제공합니다.
Tomas Langkaas 2016 년

@TomasLangkaas : 예. 그러나 다른 대답Array(n).fill(0)실제로 필요한 것이 JS 배열 인 경우 Chrome 보다 약 5 배 느리다는 것을 보여줍니다 . TypedArray를 사용할 수 있다면 .fill(0), 특히 기본 초기화 값인을 사용할 수있는 경우 보다 훨씬 빠릅니다 0. C ++과 같은 채우기 값과 길이를 취하는 생성자가없는 것 같습니다 std::vector. 0이 아닌 값의 경우 0으로 된 TypedArray를 구성한 다음 채워야합니다. : /
Peter Cordes

29

ES6을 사용하는 경우 다음 과 같이 Array.from ()을 사용할 수 있습니다 .

Array.from({ length: 3 }, () => 0);
//[0, 0, 0]

같은 결과가

Array.from({ length: 3 }).map(() => 0)
//[0, 0, 0]

때문에

Array.from({ length: 3 })
//[undefined, undefined, undefined]

23
function makeArrayOf(value, length) {
  var arr = [], i = length;
  while (i--) {
    arr[i] = value;
  }
  return arr;
}

makeArrayOf(0, 5); // [0, 0, 0, 0, 0]

makeArrayOf('x', 3); // ['x', 'x', 'x']

참고 while일반적으로보다 효율적입니다 for-in, forEach


3
하지가되어 i지역 변수의 관계없는? length값으로 전달되므로 직접 줄일 수 있습니다.
Sean Bright

3
이것이 처음에는 훌륭해 보이지만 불행히도 임의의 지점에서 값을 할당하는 것은 매우 느립니다 (예 :) arr[i] = value. 처음부터 끝까지 반복하고 사용하는 것이 훨씬 빠릅니다 arr.push(value). 나는 당신의 방법을 선호하기 때문에 성가시다.
Nick Brunt

19

객체 표기법 사용

var x = [];

제로 가득? 처럼...

var x = [0,0,0,0,0,0];

'정의되지 않음'으로 채워진 ...

var x = new Array(7);

0으로 된 obj 표기법

var x = [];
for (var i = 0; i < 10; i++) x[i] = 0;

참고로, Array의 프로토 타입을 수정하면

var x = new Array();

var y = [];

프로토 타입 수정이있을 것입니다

어쨌든, 나는이 작업의 효율성이나 속도에 지나치게 신경 쓰지 않을 것입니다 .0을 포함하는 임의의 길이의 배열을 설정하는 것보다 훨씬 더 낭비적이고 비쌀만한 일이 많이 있습니다.


5
Err ... null이 배열 에는 s 가 없습니다 –var x = new Array(7);
kangax

5
실제로, 배열은 '정의되지 않은'것이 아니라 새로운 배열 (n)으로 채워지지 않으며 단순히 배열 길이 값을 n으로 설정합니다. (new Array (1)). forEach (...)를 호출하여이를 확인할 수 있습니다. [미정의]에서 호출하는 것과 달리 forEach는 절대 실행되지 않습니다.
JussiR

4
new Array(7)않는 하지 배열 "미정 충전"을 생성한다. 길이가 7 인 배열을 만듭니다 .
RobG

1
(사실 당신이 말을하고, 매핑이 훨씬 용이했을 경우) 어떤 @RobG가 말하는 것은 중요합니다으로 당신은 당신의 대답의 부품을 재고 할 수 있습니다
아브

1
요즘 당신은 할 수 있습니다 (new Array(10)).fill(0).
하비에르 드 라 로사

18

IE 6/7/8, Firefox 3.5, Chrome 및 Opera에서 사전 할당 / 비 사전 할당, 카운트 업 / 다운 및 for / while 루프의 모든 조합을 테스트했습니다.

아래의 기능은 Firefox, Chrome 및 IE8에서 지속적으로 가장 빠르거나 매우 가까웠으며 Opera 및 IE 6에서 가장 빠르지는 않습니다. while 루프 버전이 약간 더 빠른 여러 브라우저를 찾았으므로 참조 용으로 포함했습니다.

function newFilledArray(length, val) {
    var array = [];
    for (var i = 0; i < length; i++) {
        array[i] = val;
    }
    return array;
}

또는

function newFilledArray(length, val) {
    var array = [];
    var i = 0;
    while (i < length) {
        array[i++] = val;
    }
    return array;
}

1
var array = []선언문을 실제로 for 루프의 첫 번째 부분에 쉼표로 구분하여 던질 수도 있습니다 .
damianb

나는 damianb의 제안을 좋아하지만, 증분 전에 할당과 쉼표를 넣어야합니다! `for (var i = 0; i <length; array [i] = val, i ++);
punstress

다른 모든 사람들이 두 번째로 누락 된 것을 수행하고 배열의 길이를 length이미 주어진 값으로 설정하여 끊임없이 변경되지 않도록하십시오. 내 컴퓨터에서 40ms에서 8까지 백만 길이의 0을 가져 왔습니다.
Jonathan Gray

이 솔루션을 하나의 라이너로 리팩터링하면 속도가 10-15 % 증가하는 것 같습니다. for (i = 0, array = []; i < length; ++i) array[i] = val;.. 더 적은 블록? ... 어쨌든 ... array.length새로운 배열의 길이를 길이로 설정하면 FF에서 10 % -15 %의 속도가 다시 증가하는 것 같습니다 ... Chrome에서는 속도가 두 배가되는 것 같습니다-> var i, array = []; array.length = length; while(i < length) array[i++] = val;( for루프 로 남겨두면 여전히 더 빠르지 만 ... init가 더 이상 필요하지 while
않으므로이

또한 테스트 할 때 참고할 것입니다. 필자의 테스트 사례에서 위의 최종 버전은 3 배에서 10 배 이상 빠른 속도로 빠른 것으로 보인다 ... 왜 그런지 모르겠다 ... (크롬과 FF 사이에서 테스트 된 다른 어레이 크기)
Pimp Trizkit

13

코드 실행 중에 길이가 다른 0으로 채워진 많은 배열을 만들어야하는 경우이를 달성하는 가장 빠른 방법은 이 주제에서 언급 한 방법 중 하나를 사용하여 길이 가 0 인 배열을 한 번 만드는 것입니다 당신은 알고 초과하지 않을 것입니다 그리고 필요에 따라 그 배열을 슬라이스.

예를 들어 (위의 선택된 답변의 함수를 사용하여 배열을 초기화하는 경우) 길이가 0 인 배열의 maxLength 배열을 0의 배열이 필요한 코드에 표시되는 변수로 만듭니다 .

var zero = newFilledArray(maxLength, 0);

이제 길이가 0 인 채워진 배열이 필요할 때마다이 배열을 슬라이스하십시오. requiredLength < maxLength :

zero.slice(0, requiredLength);

코드를 실행하는 동안 수천 번 채워진 배열을 수천 번 만들었으므로 프로세스 속도가 엄청나게 빨라졌습니다.


13
function zeroFilledArray(size) {
    return new Array(size + 1).join('0').split('');
}

3
new Array(size+1).join("x").split("x").map(function() { return 0; })실제 숫자를 구 하는데도 사용할 수 있습니다
Yuval

6
@Yuval 또는 그냥new Array(size+1).join('0').split('').map(Number)
Paul

11

나는 반대 할 것이 없다 :

Array.apply(null, Array(5)).map(Number.prototype.valueOf,0);
new Array(5+1).join('0').split('').map(parseFloat);

Zertosh에서 제안했지만 새로운 ES6 배열 확장에서는 기본적으로 fill메소드를 사용 하여이 작업을 수행 할 수 있습니다 . 이제 IE edge, Chrome 및 FF가 지원하지만 호환성 표를 확인하십시오.

new Array(3).fill(0)당신에게 줄 것이다 [0, 0, 0]. 배열은 new Array(5).fill('abc')객체 및 기타 배열과 같은 값으로 채울 수 있습니다 .

그 외에도 채우기로 이전 배열을 수정할 수 있습니다.

arr = [1, 2, 3, 4, 5, 6]
arr.fill(9, 3, 5)  # what to fill, start, end

그것은 당신에게 제공합니다 : [1, 2, 3, 9, 9, 6]


10

내가 일반적으로하는 방법 (그리고 놀랍습니다)은을 사용하고 Uint8Array있습니다. 예를 들어 1M 요소로 채워진 0으로 채워진 벡터 만들기 :

  var zeroFilled = [].slice.apply(new Uint8Array(1000000))

나는 Linux 사용자이고 항상 나를 위해 일했지만 Mac을 사용하는 친구에게는 0이 아닌 요소가있었습니다. 나는 그의 기계가 오작동하고 있다고 생각했지만 여전히 여기에서 우리가 발견 한 가장 안전한 방법이 있습니다.

  var zeroFilled = [].slice.apply(new Uint8Array(new Array(1000000)) 

편집

크롬 25.0.1364.160

  1. 프레데릭 고틀립-6.43
  2. 샘 바넘-4.83
  3. 엘리-3.68
  4. 여호수아 2.91
  5. 매튜 크럼 리-2.67
  6. bduran-2.55
  7. 앨런 라이스-2.11
  8. 캉 악스-0.68
  9. 티제이 크라우 더-0.67
  10. zertosh-오류

파이어 폭스 20.0

  1. 앨런 라이스-1.85
  2. 여호수아-1.82
  3. 매튜 크럼 리-1.79
  4. bduran-1.37
  5. 프레데릭 고틀립-0.67
  6. 샘 바넘-0.63
  7. 엘리-0.59
  8. 카 톡스-0.13
  9. 티제이 크라우 더-0.13
  10. zertosh-오류

Node.js와 같은 가장 중요한 테스트가 없습니다. Chrome 벤치 마크와 가깝습니다.


이것은 내 손가락과 눈에 가장 효율적인 방법입니다. 그러나 Chrome의 경우 매우 느립니다 (이 jsperf. 99 % 느림).
Orwellophile

1
친구의 Mac에서 문제가 stackoverflow.com/questions/39129200/ 과 관련이 있는지 궁금합니다. 또는 Array.slice가 UInt8Array를 처리하지 않고 초기화되지 않은 메모리가 누출됩니까? (보안 문제!).
robocat

@robocat 잘 잡아라! 잘 기억한다면 Node.js 0.6 또는 0.8을 사용하고있었습니다. 우리는 어떤 종류의 누출에 대해 생각했지만 생산 스택으로 그것을 재현 할 수 없었으므로 무시하기로 결정했습니다.
durum

10

사용 lodash 또는 밑줄을

_.range(0, length - 1, 0);

또는 배열이 있고 길이가 같은 배열을 원할 경우

array.map(_.constant(0));

밑줄을 사용 하면서이 답변을 추가하게되어 기쁘고, 이것에 대한 것이 있다는 것을 알았지 만 아직 찾을 수 없었습니다. 난 그냥 이것을 사용하여 객체의 배열을 만들 수 있기를 바랍니다
PandaWood

@ 팬더 우드 _.range (0, 길이 -1, 0) .map (Object.new), 나는 생각합니다.
djechlin

이어야 _.range(0, length, 0)한다고 믿습니다. Lodash는 최종 가치를 배제합니다
user4815162342

9

ES6 솔루션 :

[...new Array(5)].map(x => 0); // [0, 0, 0, 0, 0]

8

ECMAScript2016 기준으로 대규모 어레이에 대한 명확한 선택이 있습니다.

이 답변은 여전히 ​​Google 검색에서 맨 위에 표시되므로 2017에 대한 답변입니다.

다음 은이 질문에 지금까지 제안 된 많은 것을 포함하여 수십 가지 인기있는 메소드 가있는 현재 jsbench 입니다. 더 나은 방법을 찾으면 추가, 포크 및 공유하십시오.

임의의 길이의 0으로 채워진 배열을 만드는 가장 효율적인 방법은 없습니다. 속도 또는 명확성 및 유지 관리 성을 위해 최적화 할 수 있습니다. 프로젝트의 요구에 따라보다 효율적인 선택으로 간주 될 수 있습니다.

속도를 최적화 할 때 다음을 수행하려고합니다. 리터럴 구문을 사용하여 배열을 작성하십시오. 길이를 설정하고 반복 변수를 초기화하고 while 루프를 사용하여 배열을 반복하십시오. 다음은 예입니다.

const arr = [];
arr.length = 120000;
let i = 0;
while (i < 120000) {
  arr[i] = 0;
  i++;
}

가능한 다른 구현은 다음과 같습니다.

(arr = []).length = n;
let i = 0;
while (i < n) {
    arr[i] = 0;
    i++;
}

그러나 실제로 두 번째 이식을 사용하는 것은 명확하지 않으며 배열 변수에서 블록 범위를 유지할 수 없으므로 강력히 권장하지 않습니다.

이것들은 for 루프로 채우는 것보다 훨씬 빠르며 표준 방법보다 약 90 % 빠릅니다.

const arr = Array(n).fill(0);

그러나이 채우기 방법은 명확성, 간결성 및 유지 관리 성으로 인해 더 작은 어레이에 가장 효율적인 선택입니다. 수천 가지 이상의 길이를 가진 배열을 많이 만들지 않으면 성능 차이로 인해 죽지 않을 것입니다.

몇 가지 중요한 참고 사항. 대부분의 스타일 가이드는 varES6 이상을 사용할 때 특별한 이유 없이는 더 이상 사용 하지 않는 것이 좋습니다 . const재정의되지 않는 변수와 변수에 사용하십시오 let. MDN에어 비앤비의 스타일 가이드 모범 사례에 대한 자세한 내용은 갈 좋은 장소입니다. 질문은 구문에 관한 것이 아니라 JS를 처음 접하는 사람들이 구식의 새로운 답변을 검색 할 때 이러한 새로운 표준에 대해 아는 것이 중요합니다.


8

완전히 새로운 배열을 만들려면

new Array(arrayLength).fill(0);

기존 배열의 끝에 일부 값을 추가하려면

[...existingArray, ...new Array(numberOfElementsToAdd).fill(0)]

//**To create an all new Array**

console.log(new Array(5).fill(0));

//**To add some values at the end of an existing Array**

let existingArray = [1,2,3]

console.log([...existingArray, ...new Array(5).fill(0)]);


6

답변 에서이 방법을 보지 못 했으므로 여기에 있습니다.

"0".repeat( 200 ).split("").map( parseFloat )

결과적으로 길이가 200 인 값이 0 인 배열을 얻게됩니다.

[ 0, 0, 0, 0, ... 0 ]

이 코드의 성능에 대해 잘 모르겠지만 비교적 작은 배열에 사용하면 문제가되지 않습니다.


5
솔루션의 다양성에 가장 빠르거나 짧지는 않지만 훌륭한 기여를합니다.
7vujy0f0hy


4

concat버전은 Chrome 테스트 (2013-03-21)에서 훨씬 빠릅니다. 10,000,000 개의 요소에 대해 약 200ms vs. 직선 초기화에 대한 675

function filledArray(len, value) {
    if (len <= 0) return [];
    var result = [value];
    while (result.length < len/2) {
        result = result.concat(result);
    }
    return result.concat(result.slice(0, len-result.length));
}

보너스 : 배열을 문자열로 채우려면이 방법을 간결하게 수행하는 간결한 방법입니다 concat.

function filledArrayString(len, value) {
    return new Array(len+1).join(value).split('');
}

2
알았어. 새로운 Array (len)를 사용하는 것보다 훨씬 빠릅니다. 그러나! Chrome에서 해당 데이터에 대한 후속 읽기가 상당히 오래 걸린다는 것을 알았습니다. 다음은 내가 의미하는 바를 나타내는 몇 가지 타임 스탬프입니다. 컨볼 루션 완료
Brooks

4

TJ Crowder가 큰 대답을 테스트하고 Chrome에서 테스트보다 성능이 우수한 concat 솔루션을 기반으로 재귀 병합을 수행했습니다 (다른 브라우저는 테스트하지 않았습니다).

function makeRec(len, acc) {
    if (acc == null) acc = [];
    if (len <= 1) return acc;
    var b = makeRec(len >> 1, [0]);
    b = b.concat(b);
    if (len & 1) b = b.concat([0]);
    return b;
},

로 메소드를 호출하십시오 makeRec(29).



4

그것은 지적 가치, 수도 Array.prototype.fill의 일환으로 추가되었다 ECMAScript를 6 (하모니) 제안 . 스레드에 언급 된 다른 옵션을 고려하기 전에 아래에 작성된 polyfill을 사용하고 싶습니다.

if (!Array.prototype.fill) {
  Array.prototype.fill = function(value) {

    // Steps 1-2.
    if (this == null) {
      throw new TypeError('this is null or not defined');
    }

    var O = Object(this);

    // Steps 3-5.
    var len = O.length >>> 0;

    // Steps 6-7.
    var start = arguments[1];
    var relativeStart = start >> 0;

    // Step 8.
    var k = relativeStart < 0 ?
      Math.max(len + relativeStart, 0) :
      Math.min(relativeStart, len);

    // Steps 9-10.
    var end = arguments[2];
    var relativeEnd = end === undefined ?
      len : end >> 0;

    // Step 11.
    var final = relativeEnd < 0 ?
      Math.max(len + relativeEnd, 0) :
      Math.min(relativeEnd, len);

    // Step 12.
    while (k < final) {
      O[k] = value;
      k++;
    }

    // Step 13.
    return O;
  };
}

4

가장 짧은 for 루프 코드

a=i=[];for(;i<100;)a[i++]=0;

edit:
for(a=i=[];i<100;)a[i++]=0;
or
for(a=[],i=100;i--;)a[i]=0;

안전한 var 버전

var a=[],i=0;for(;i<100;)a[i++]=0;

edit:
for(var i=100,a=[];i--;)a[i]=0;

2
길이가 정의 된 변수 인 n경우이 길이는 더 짧습니다.for(var a=[];n--;a[n]=0);
Tomas Langkaas


3

가장 빠른 기능은 다음과 같습니다.

function newFilledArray(len, val) {
    var a = [];
    while(len--){
        a.push(val);
    }
    return a;
}

var st = (new Date()).getTime();
newFilledArray(1000000, 0)
console.log((new Date()).getTime() - st); // returned 63, 65, 62 milliseconds

기본 푸시 앤 시프트를 사용하여 배열에 항목을 추가하면 배열 범위를 선언하고 각 항목을 참조하여 값을 설정하는 것보다 훨씬 빠릅니다 (약 10 배).

fyi : firebug (firefox extension)에서 이것을 실행할 때 카운트 다운되는 첫 번째 루프로 일관되게 더 빠른 시간을 얻습니다.

var a = [];
var len = 1000000;
var st = (new Date()).getTime();
while(len){
    a.push(0);
    len -= 1;
}
console.log((new Date()).getTime() - st); // returned 863, 894, 875 milliseconds
st = (new Date()).getTime();
len = 1000000;
a = [];
for(var i = 0; i < len; i++){
    a.push(0);
}
console.log((new Date()).getTime() - st); // returned 1155, 1179, 1163 milliseconds

TJ Crowder가 무엇을하는지 알고 싶습니다. :-)


당신은 그것을 변경하여 빠르게 만들 수 있습니다 while (len--)54ms 정도까지 60ms 대해에서 내 처리 시간을했다 ..
nickf

Matthew Crumbly의 답변은 여전히 ​​실제로 이보다 뛰어납니다 (30ms)!
nickf

3

나는이 프로토가 어딘가에 있음을 알았습니다 :)

Array.prototype.init = function(x,n)
{
    if(typeof(n)=='undefined') { n = this.length; }
    while (n--) { this[n] = x; }
    return this;
}

var a = (new Array(5)).init(0);

var b = [].init(0,4);

편집 : 테스트

여호수아와 다른 방법들에 대한 반응으로 나는 자체 벤치마킹을 수행했으며,보고 된 것과는 완전히 다른 결과를보고 있습니다.

내가 테스트 한 것은 다음과 같습니다.

//my original method
Array.prototype.init = function(x,n)
{
    if(typeof(n)=='undefined') { n = this.length; }
    while (n--) { this[n] = x; }
    return this;
}

//now using push which I had previously thought to be slower than direct assignment
Array.prototype.init2 = function(x,n)
{
    if(typeof(n)=='undefined') { n = this.length; }
    while (n--) { this.push(x); }
    return this;
}

//joshua's method
function newFilledArray(len, val) {
    var a = [];
    while(len--){
        a.push(val);
    }
    return a;
}

//test m1 and m2 with short arrays many times 10K * 10

var a = new Date();
for(var i=0; i<10000; i++)
{
    var t1 = [].init(0,10);
}
var A = new Date();

var b = new Date();
for(var i=0; i<10000; i++)
{
    var t2 = [].init2(0,10);
}
var B = new Date();

//test m1 and m2 with long array created once 100K

var c = new Date();
var t3 = [].init(0,100000);
var C = new Date();

var d = new Date();
var t4 = [].init2(0,100000);
var D = new Date();

//test m3 with short array many times 10K * 10

var e = new Date();
for(var i=0; i<10000; i++)
{
    var t5 = newFilledArray(10,0);
}
var E = new Date();

//test m3 with long array created once 100K

var f = new Date();
var t6 = newFilledArray(100000, 0)
var F = new Date();

결과 :

IE7 deltas:
dA=156
dB=359
dC=125
dD=375
dE=468
dF=412

FF3.5 deltas:
dA=6
dB=13
dC=63
dD=8
dE=12
dF=8

따라서 내 계산으로 인해 일반적으로 느리게 진행되지만 FF에서는 더 긴 배열에서는 더 잘 수행되지만 IE에서는 더 나빠져서 일반적으로 짜증납니다 (quel surprise).


방금 이것을 테스트했습니다. 두 번째 방법 ( b = []...)은 첫 번째 방법 보다 10-15 % 빠르지 만 Joshua의 답변보다 10 배 이상 느립니다.
nickf

나는 이것이 고대 포스트 라는 것을 안다 . 그러나 아마도 그것은 나와 같은 다른 사람들에게 여전히 관심이 있습니다. 따라서 나는 프로토 타입 함수에 ADITION을 제안하고 싶습니다 :을 포함 else {this.length=n;}애프터 this.length-check. 필요한 경우 init다른 길이로 재 다이얼 할 때 기존 어레이 를 줄 n입니다.
cars10m

2

익명의 기능 :

(function(n) { while(n-- && this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]

for-loop를 사용하면 약간 짧아집니다.

(function(n) { for(;n--;this.push(0)); return this; }).call([], 5);
// => [0, 0, 0, 0, 0]

어떤 Object것과 도 작동하며 내부의 내용 만 변경하십시오 this.push().

기능을 저장할 수도 있습니다.

function fill(size, content) {
  for(;size--;this.push(content));
  return this;
}

다음을 사용하여 호출하십시오.

var helloArray = fill.call([], 5, 'hello');
// => ['hello', 'hello', 'hello', 'hello', 'hello']

기존 배열에 요소 추가 :

var helloWorldArray = fill.call(helloArray, 5, 'world');
// => ['hello', 'hello', 'hello', 'hello', 'hello', 'world', 'world', 'world', 'world', 'world']

성능 : http://jsperf.com/zero-filled-array-creation/25

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