755 votes

Moyen le plus efficace pour créer un zéro rempli le tableau JavaScript ?

Ce qui est le moyen le plus efficace pour créer une longueur arbitraire zéro rempli le tableau en JavaScript ?

764voto

Oriol Points 20803

ES6 introduit `` . Il peut être utilisé comme ceci :

Vous ne savez pas si c’est rapide, mais je l’aime parce qu’il est court et autodescriptif.

403voto

zertosh Points 1511

Bien qu’il s’agit d’un ancien sujet, j’ai voulu y ajouter mes 2 cents. Pas sûr comment lent/rapide il s’agit, mais c’est une doublure d’un rapide. Voici ce que je fais :

Si je veux remplir à l’avance avec un certain nombre :

Si je veux remplir à l’avance avec une chaîne :


Autres réponses ont suggéré :

mais si vous voulez 0 (le nombre) et non pas « 0 » (zéro à l’intérieur d’une chaîne), vous pouvez :

55voto

T.J. Crowder Points 285826

(Note ajoutée août 2013: Cette réponse de 2009 concernent du JavaScript générique Array type. Il ne concerne pas les nouveaux tapé des tableaux définis dans l'ES6 [et maintenant disponible dans la plupart des navigateurs], comme Int32Array . Aussi, il peut faire une grande différence pour certaines implémentations de la façon dont vous créez le tableau. Google Chrome, moteur V8, en particulier, tente de l'utiliser, hautement efficace, contigu de mémoire tableau, si elle le juge peut, le passage à l'objet-tableau de base uniquement lorsque c'est nécessaire.)

Avec la plupart des langues, il serait pré-allouer, puis zéro de remplissage, comme ceci:

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

Mais, les tableaux JavaScript ne sont pas vraiment des tableaux, ils sont la clé/valeur des cartes, comme tous les autres objets en JavaScript, donc il n'y a pas de "pré-allouer" (réglage de la longueur de n'allouer que de nombreux logements à remplir), il n'y a aucune raison de croire que les avantages du compte à rebours à zéro (ce qui est juste pour faire la comparaison dans la boucle rapide) n'est pas compensé par l'ajout de touches dans l'ordre inverse lors de la mise en œuvre pourrait bien avoir optimisé leur manipulation des touches associées à des tableaux sur la théorie que vous aurez généralement le faire dans l'ordre.

En fait, Matthieu Crumley a souligné que le compte à rebours est nettement plus lent sur Firefox que de compter jusqu', je peux confirmer — c'est la matrice de partie (boucle vers le bas à zéro est encore plus rapide que la boucle jusqu'à une limite en var). Apparemment ajoutant les éléments du tableau dans l'ordre inverse est une lente op sur Firefox. En fait, les résultats varient très peu en JavaScript mise en œuvre (ce qui n'est pas surprenant). Voici un moyen rapide et sale page de test (ci-dessous) pour le navigateur implémentations (très sale, ne donne pas pendant les tests, donc peu de commentaires et va à l'encontre de script limites de temps). Je recommande rafraîchissante entre les tests; FF (au moins) ralentit à répéter les tests si vous ne le faites pas.

Il est relativement compliqué que la version qui utilise Array#concat est plus rapide qu'une droit init sur FF que de quelque part entre 1 000 et 2 000 élément des tableaux. Sur google Chrome, moteur V8, bien que, droite init est la victoire de tous les temps...

Voici la page de test (live copie):

<!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>

26voto

kangax Points 19954
<pre><code></code><p><code></code><code></code><code></code>, etc..</p></pre>

20voto

Matthew Crumley Points 47284

J'ai testé toutes les combinaisons de pré-attribution/pas de pré-affectation, à compter de/, et/boucles while dans IE 6/7/8, Firefox 3.5, Chrome et Opera.

Les fonctions ci-dessous a toujours été le plus rapide ou très proche dans Firefox, Chrome et IE8, et pas beaucoup plus lent que la manière la plus rapide dans l'Opéra et IE 6. C'est aussi la plus simple et la plus claire à mon avis. J'ai trouvé plusieurs navigateurs où la boucle while version est légèrement plus rapide, donc je suis, y compris pour référence.

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

ou

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X