122 votes

Diviser un tableau JS en N tableaux

Imaginons que j'ai un tableau JS comme celui-ci :

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];

Ce que je veux, c'est diviser ce tableau en N tableaux plus petits. Par exemple :

split_list_in_n(a, 2)
[[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11]]

For N = 3:
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]

For N = 4:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]

For N = 5:
[[1, 2, 3], [4, 5], [6, 7], [8, 9], [10, 11]]

Pour Python, j'ai ceci :

def split_list_in_n(l, cols):
    """ Split up a list in n lists evenly size chuncks """
    start = 0
    for i in xrange(cols):
        stop = start + len(l[i::cols])
        yield l[start:stop]
        start = stop

Pour JS, la meilleure solution que j'ai pu trouver est une fonction récursive, mais je ne l'aime pas parce qu'elle est compliquée et laide. Cette fonction interne renvoie un tableau comme celui-ci [1, 2, 3, null, 4, 5, 6, null, 7, 8], et ensuite je dois le reboucler et le diviser manuellement. (Ma première tentative renvoyait ceci : [1, 2, 3, [4, 5, 6, [7, 8, 9]], et j'ai décidé de le faire avec le séparateur null).

function split(array, cols) {
    if (cols==1) return array;
    var size = Math.ceil(array.length / cols);
    return array.slice(0, size).concat([null]).concat(split(array.slice(size), cols-1));
}

En voici un exemple en jsfiddle : http://jsfiddle.net/uduhH/

Comment feriez-vous ? Merci d'avance !

158voto

georg Points 52691

Vous pouvez faire en sorte que les tranches soient "équilibrées" (les longueurs des sous-ensembles diffèrent le moins possible) ou "paires" (tous les sous-ensembles sauf le dernier ont la même longueur) :

function chunkify(a, n, balanced) {

    if (n < 2)
        return [a];

    var len = a.length,
            out = [],
            i = 0,
            size;

    if (len % n === 0) {
        size = Math.floor(len / n);
        while (i < len) {
            out.push(a.slice(i, i += size));
        }
    }

    else if (balanced) {
        while (i < len) {
            size = Math.ceil((len - i) / n--);
            out.push(a.slice(i, i += size));
        }
    }

    else {

        n--;
        size = Math.floor(len / n);
        if (len % size === 0)
            size--;
        while (i < size * n) {
            out.push(a.slice(i, i += size));
        }
        out.push(a.slice(size * n));

    }

    return out;
}

///////////////////////

onload = function () {
    function $(x) {
        return document.getElementById(x);
    }

    function calc() {
        var s = +$('s').value, a = [];
        while (s--)
            a.unshift(s);
        var n = +$('n').value;
        $('b').textContent = JSON.stringify(chunkify(a, n, true))
        $('e').textContent = JSON.stringify(chunkify(a, n, false))
    }

    $('s').addEventListener('input', calc);
    $('n').addEventListener('input', calc);
    calc();
}

<p>slice <input type="number" value="20" id="s"> items into
<input type="number" value="6" id="n"> chunks:</p>
<pre id="b"></pre>
<pre id="e"></pre>

62voto

Senthe Points 1123

Je pense que cette façon d'utiliser l'épissure est la plus propre :

function splitToChunks(array, parts) {
    let result = [];
    for (let i = parts; i > 0; i--) {
        result.push(array.splice(0, Math.ceil(array.length / i)));
    }
    return result;
}

// Example:

const example = [0,1,2,3,4,5,6,7,8,9,10,11,12]

console.log(splitToChunks([...example], 3))
console.log(splitToChunks([...example], 5))

Par exemple, pour parts = 3 Dans le cas contraire, vous prendriez 1/3, puis 1/2 de la partie restante, puis le reste du tableau. Math.ceil garantit qu'en cas de nombre impair d'éléments, ils iront dans les morceaux les plus anciens.

(Note : l'appel à .splice sur un tableau modifie directement sa longueur. Pour éviter de détruire votre tableau initial, vous pouvez utiliser sa copie temporaire peu profonde : const copiedArray = [ ...originalArray ] )

19voto

bagbee Points 221
function split(array, n) {
  let [...arr]  = array;
  var res = [];
  while (arr.length) {
    res.push(arr.splice(0, n));
  }
  return res;
}

16voto

pimvdb Points 66332

Je viens de réaliser une implémentation itérative de l'algorithme : http://jsfiddle.net/ht22q/ . Il passe vos tests.

function splitUp(arr, n) {
    var rest = arr.length % n, // how much to divide
        restUsed = rest, // to keep track of the division over the elements
        partLength = Math.floor(arr.length / n),
        result = [];

    for(var i = 0; i < arr.length; i += partLength) {
        var end = partLength + i,
            add = false;

        if(rest !== 0 && restUsed) { // should add one element for the division
            end++;
            restUsed--; // we've used one division element now
            add = true;
        }

        result.push(arr.slice(i, end)); // part of the array

        if(add) {
            i++; // also increment i in the case we added an extra element for division
        }
    }

    return result;
}

10voto

Bursos Points 305

Vous pouvez le réduire à une matrice. L'exemple ci-dessous divise le tableau ( arr ) en une matrice de tableaux à deux positions. Si vous souhaitez d'autres tailles, il suffit de modifier la valeur 2 sur la deuxième ligne :

target.reduce((memo, value, index) => {
  if (index % 2 === 0 && index !== 0) memo.push([])
  memo[memo.length - 1].push(value)
  return memo
}, [[]])

J'espère que cela vous aidera !

EDIT : Parce que certaines personnes commentent encore, cela ne répond pas à la question puisque j'étais en train de corriger le problème. la taille de chaque morceau au lieu du nombre de morceaux Je veux. Voici le code qui explique ce que j'essaie d'expliquer dans la section des commentaires : L'utilisation de la fonction target.length .

// Chunk function

const chunk = (target, size) => {
  return target.reduce((memo, value, index) => {
    // Here it comes the only difference
    if (index % (target.length / size) == 0 && index !== 0) memo.push([])
    memo[memo.length - 1].push(value)
    return memo
  }, [[]])
}

// Usage

write(chunk([1, 2, 3, 4], 2))
write(chunk([1, 2, 3, 4], 4))

// For rendering pruposes. Ignore
function write (content) { document.write(JSON.stringify(content), '</br>') }

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