1046 Stimmen

Array in Stücke aufteilen

Nehmen wir an, dass ich ein Javascript-Array habe, das wie folgt aussieht:

["Element 1","Element 2","Element 3",...]; // with close to a hundred elements.

Welcher Ansatz wäre angemessen, um das Array in viele kleinere Arrays mit, sagen wir, höchstens 10 Elementen aufzuteilen?

1voto

Fernando Leal Punkte 9475

Eine effiziente Lösung besteht darin, die Lösung mit Scheibe y push by indexChunk wird die Lösung in Stücke geteilt:

function splitChunks(sourceArray, chunkSize) {
  if(chunkSize <= 0)
    throw "chunkSize must be greater than 0";
  let result = [];
  for (var i = 0; i < sourceArray.length; i += chunkSize) {
    result[i / chunkSize] = sourceArray.slice(i, i + chunkSize);
  }
  return result;
}

let ar1 = [
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
];

console.log("Split in chunks with 4 size", splitChunks(ar1, 4));
console.log("Split in chunks with 7 size", splitChunks(ar1, 7));

1voto

AGE Punkte 3702

Ich habe das Folgende erstellt JSFiddle um meinen Ansatz für Ihre Frage zu demonstrieren.

(function() {
  // Sample arrays
  var //elements = ["0", "1", "2", "3", "4", "5", "6", "7"],
      elements = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43"];

  var splitElements = [],
      delimiter = 10; // Change this value as needed

  // parameters: array, number of elements to split the array by
  if(elements.length > delimiter){
    splitElements = splitArray(elements, delimiter);
  }
  else {
    // No need to do anything if the array's length is less than the delimiter
    splitElements = elements;
  }

  //Displaying result in console
  for(element in splitElements){
    if(splitElements.hasOwnProperty(element)){
        console.log(element + " | " + splitElements[element]);
    }
  }
})();

function splitArray(elements, delimiter) {
  var elements_length = elements.length;

  if (elements_length > delimiter) {
    var myArrays = [], // parent array, used to store each sub array
      first = 0, // used to capture the first element in each sub array
      index = 0; // used to set the index of each sub array

    for (var i = 0; i < elements_length; ++i) {
      if (i % delimiter === 0) {
        // Capture the first element of each sub array from the original array, when i is a modulus factor of the delimiter.
        first = i;
      } else if (delimiter - (i % delimiter) === 1) {
      // Build each sub array, from the original array, sliced every time the i one minus the modulus factor of the delimiter.
        index = (i + 1) / delimiter - 1;
        myArrays[index] = elements.slice(first, i + 1);
      }
      else if(i + 1 === elements_length){
        // Build the last sub array which contain delimiter number or less elements
        myArrays[index + 1] = elements.slice(first, i + 1);
      }
    }
    // Returned is an array of arrays
    return myArrays;
  }
}

Zunächst einmal habe ich zwei Beispiele: ein Array mit weniger als acht Elementen und ein Array mit mehr als acht Elementen (kommentieren Sie das, was Sie nicht verwenden möchten).

Dann prüfe ich die Größe des Arrays, einfach, aber wichtig, um zusätzliche Berechnungen zu vermeiden. Wenn das Array die Kriterien erfüllt (Arraygröße > delimiter ) gehen wir in die splitArray Funktion.

El splitArray Funktion nimmt das Trennzeichen (d.h. 8, da Sie durch dieses trennen wollen) und das Array selbst auf. Da wir die Array-Länge oft wiederverwenden, speichere ich sie in einer Variablen, ebenso wie die first y last .

first steht für die Position des ersten Elements in einem Array. Dieses Array ist ein Array, das aus 8 Elementen besteht. Um also das erste Element zu bestimmen, verwenden wir die Modulus-Operator .

myArrays ist das Array der Arrays. Darin wird bei jedem Index ein beliebiges Unterfeld der Größe 8 oder kleiner gespeichert. Dies ist die Schlüsselstrategie für den folgenden Algorithmus.

index stellt den Index für die myArrays variabel. Jedes Mal, wenn ein Unterfeld mit 8 oder weniger Elementen gespeichert werden soll, muss es im entsprechenden Index gespeichert werden. Wenn wir also 27 Elemente haben, bedeutet das 4 Arrays. Das erste, zweite und dritte Array haben jeweils 8 Elemente. Das letzte hat nur 3 Elemente. Also index sind 0, 1, 2 bzw. 3.

Der schwierige Teil ist einfach, die Mathematik zu verstehen und sie so gut wie möglich zu optimieren. Zum Beispiel else if (delimiter - (i % delimiter) === 1) Dies dient dazu, das letzte Element zu finden, das in das Array aufgenommen werden soll, wenn ein Array voll ist (Beispiel: 10 Elemente enthalten).

Dieser Code funktioniert für jedes einzelne Szenario, Sie können sogar die delimiter um eine beliebige Array-Größe zu erhalten, die Sie wünschen. Ziemlich cool, oder :-)

Haben Sie Fragen? Fragen Sie einfach in den Kommentaren unten.

1voto

Chris Martin Punkte 1821

Ich habe dies gerade mit Hilfe einer groupBy-Funktion geschrieben.

// utils
const group = (source) => ({
  by: (grouping) => {
    const groups = source.reduce((accumulator, item) => {
      const name = JSON.stringify(grouping(item));
      accumulator[name] = accumulator[name] || [];
      accumulator[name].push(item);
      return accumulator;
    }, {});

    return Object.keys(groups).map(key => groups[key]);
  }
});

const chunk = (source, size) => group(source.map((item, index) => ({ item, index })))
.by(x => Math.floor(x.index / size))
.map(x => x.map(v => v.item));

// 103 items
const arr = [6,2,6,6,0,7,4,9,3,1,9,6,1,2,7,8,3,3,4,6,8,7,6,9,3,6,3,5,0,9,3,7,0,4,1,9,7,5,7,4,3,4,8,9,0,5,1,0,0,8,0,5,8,3,2,5,6,9,0,0,1,5,1,7,0,6,1,6,8,4,9,8,9,1,6,5,4,9,1,6,6,1,8,3,5,5,7,0,8,3,1,7,1,1,7,6,4,9,7,0,5,1,0];

const chunks = chunk(arr, 10);

console.log(JSON.stringify(chunks));

1voto

Bernardo Dal Corno Punkte 1382

Mit Verspätung, hier sind meine zwei Cent. Wie schon viele gesagt haben, würde ich zuerst an etwas denken wie

chunker = (a,n) => [...Array(Math.ceil(a.length/n))].map((v,i) => a.slice(i*n, (i+1)*n))

Aber was mir besser gefällt und was ich hier noch nicht gesehen habe, ist dies:

chunker = (n) => (r,v,i) => (c = Math.floor(i/n), (r[c] = r[c] || []).push(v), r)

console.log(arr.reduce(chunker(3), []))

mit längerer Variante

chunker = (a, n) => a.reduce((r,v,i) => {
  c = Math.floor(i/n); // which chunk it belongs to
  (r[c] = r[c] || []).push(v)
  return r
}, [])

console.log(chunker(arr, 3))

Erklärungen

  1. Die übliche Antwort wird zuerst die Anzahl der Chunks bestimmen und dann Slices des ursprünglichen Arrays basierend auf dem Chunk und der Größe der einzelnen Chunks erhalten

  2. Die Chunker-Reducer-Funktion geht jedes Element durch und fügt es in das entsprechend ausgewertete Array des Chunks ein.

Die Leistung ist fast die gleiche, wobei die Reduktionsmethode im Durchschnitt 4 % langsamer ist, soweit ich sehen konnte.

PS: Reduzieren hat den Vorteil, dass sich die Gruppierungskriterien leicht ändern lassen. In der Frage und den Beispielen ist das Kriterium benachbarte Zellen (und das Mapping verwendet dafür Slice). Sie können aber auch "Zyklen" verwenden, z. B. mod (%-Operator) oder andere mathematische Formeln

Beim erneuten Lesen wurde mir klar, dass die Formel auch ein Parameter sein kann, was zu einer allgemeineren Lösung führt und 2 Funktionen erfordert, um die Antwort zu erhalten:

splitter = (a, f) => a.reduce((r,v,i) => { // math formula and/or function
  c = f(v, i) || 0; // custom formula, receiving each value and index
  (r[c] = r[c] || []).push(v)
  return r
}, [])

chunker = (a, n) => splitter(a, (v,i) => Math.floor(i/n))

console.log(chunker(arr, 3))
console.log(splitter(arr, (v,i) => v % 2))  // is it even or odd?

Mit kleinen Änderungen splitter könnte auch für die Erstellung von benannten Arrays alias Objekten verwendet werden, wobei die Funktion Strings anstelle von Zahlen zurückgibt :)

1voto

AaronCoding Punkte 156

Hier ist eine Version mit Tail-Rekursion und Array-Destrukturierung.

Bei weitem nicht die schnellste Leistung aber ich finde es amüsant, dass js das jetzt tun kann. Auch wenn es nicht dafür optimiert ist :(

const getChunks = (arr, chunk_size, acc = []) => {
    if (arr.length === 0) { return acc }
    const [hd, tl] = [ arr.slice(0, chunk_size), arr.slice(chunk_size) ]
    return getChunks(tl, chunk_size, acc.concat([hd]))
}

// USAGE
const my_arr = [1,2,3,4,5,6,7,8,9]
const chunks = getChunks(my_arr, 2)
console.log(chunks) // [[1,2],[3,4], [5,6], [7,8], [9]]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X