development

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

big-blog 2020. 2. 10. 22:19
반응형

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


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


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

new Array(len).fill(0);

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

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


이것은 오래된 실이지만 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]

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

지금까지 아무도 언급하지 않은 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()원하는 값으로 ped합니다. 단계별로 분류 :

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

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

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

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

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

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


참고 : 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>

가장 빠른

Array(n).fill(0)

(16 자), 여기서 n배열의 크기는


2018.10.28 다른 답변에서 15 건의 제안을 성능 비교했습니다. 테스트는 Chrome 69.0.3497, Safari 12.0 (13606.2.11) 및 Firefox 63.0 (64 비트)의 세 가지 브라우저에서 Mac OS X 10.13.6 High Sierra에서 수행되었습니다.

n = 100000의 결과

아래에서 가장 빠른 브라우저 (사파리)에 대한 결과를 표시합니다 :

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

모든 브라우저에서 가장 빠른 솔루션은 M 이지만 "일반 배열"은 아니지만 매우 빠릅니다.-Safari 33.8k 작업 / 초, Chrome 5.2k, FF 3.5k,

일반적인 어레이를위한 가장 빠른 솔루션 :

  • Safari 5.5k 및 Chrome 1.1k의 AB (와 유사 함) (Firefox A 0.1k, B 0.06k)
  • Firefox 0.6k F (Safari 3.1k, Chrome 1.1k)
  • Chrome 및 Safari A, B, F의 결과는 비슷했습니다.

가장 느린 해결책 :

  • Safari 0.02k 및 Firefox 0.04k 용 G (Chrome 0.1k)
  • Chrome 0.04k 용 D (Safari 0.33k, Firefox 0.15k)

솔루션 N 은 Firefox 및 Chrome에서만 작동합니다.

n = 10에 대한 결과

가장 빠른 :

  • M 은 Chrome 17.3M 및 Safari 13.3M (Firefox 4.7M)에서 가장 빠릅니다.
  • A, B 는 Firefox 16.9M (Chrome 15.6M, Safari 3.5M)에서 비슷하고 빠릅니다.

가장 느림 :

  • Safari 0.35M의 경우 O
  • Chrome 용 K 0.35M
  • Firefox 0.31M의 경우 N

결론

  • 모든 브라우저에서 가장 빠른 솔루션 ( nFirefox에서는 작은 것 제외 )은 M let a = new Float32Array(n) (일반 배열은 아니지만)-가장 빠른 브라우저는 Safari ( nChrome보다 6 배 이상, 파이어 폭스보다 9 배 더 빠름) 인 Safari였습니다.
  • 일반적인 배열의 경우 선호되는 솔루션은 A let a = Array(n).fill(0) (빠른 코드)입니다.

여기서 컴퓨터 에서 테스트를 수행 할 수 있습니다 .


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

var ary = new Uint8Array(10);

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


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]

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


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;
}

객체 표기법 사용

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을 포함하는 임의의 길이의 배열을 설정하는 것보다 훨씬 더 낭비적이고 비싸지는 다른 많은 것들이 있습니다.


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

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

예를 들어 (위의 선택된 답변에서 함수를 사용하여 배열을 초기화) 길이가 0 인 배열을 maxLength 길이의 배열로 작성 하십시오.

var zero = newFilledArray(maxLength, 0);

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

zero.slice(0, requiredLength);

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


나는 반대 할 것이 없다 :

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]


내가 일반적으로하는 방법 (그리고 놀랍습니다)은을 사용하고 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 벤치 마크와 가깝습니다.


ES6 솔루션 :

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

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를 처음 접하는 사람들이 구식의 새로운 답변을 검색 할 때 이러한 새로운 표준에 대해 아는 것이 중요합니다.


사용 lodash 또는 밑줄을

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

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

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

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

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)]);


무엇에 대해 new Array(51).join('0').split('')?


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

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

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

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

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


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

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가 무엇을하는지 알고 싶습니다. :-)


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('');
}

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).


가장 짧은 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;

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

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).


그것은 지적 가치, 수도 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;
  };
}

let filled = [];
filled.length = 10;
filled.fill(0);

console.log(filled);


나는 단지 다음을 사용한다 :

var arr = [10];
for (var i=0; i<=arr.length;arr[i] = i, i++);

익명의 기능 :

(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

참고 URL : https://stackoverflow.com/questions/1295584/most-efficient-way-to-create-a-zero-filled-javascript-array



반응형