Home > Blockchain >  Javascript - chunk arrays for custom size
Javascript - chunk arrays for custom size

Time:09-22

I have an array like:

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

How I can reorder this array with the following rules:

  1. myArray[0][0] to reduce size to 2 elements (values 1,2 stay, 3,4 goes to next array)
  2. keep all values just move extra array elements to the next array, but all arrays need to keep the current number of elements except last

WHat I already try is:

function conditionalChunk(array, size, rules = {}) {
  let copy = [...array],
      output = [],
      i = 0;

  while (copy.length)
    output.push( copy.splice(0, rules[i  ] ?? size) )

  return output
}
    conditionalChunk(myArray, 3, {0:2});

but in that case, I need to put rules for all arrays in the array, I need to know a number of elements for all arrays in the array, and that's what I want to avoid.

Is there any elegant way to do that?

CodePudding user response:

Here is what I came up with. Paste the code into the chrome console and test it.

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

//Getting initial lengths of inner arrays [4, 2, 3, 1]
var lengths = [];
for(var arr of myArray) {
    lengths.push(arr.length);
}

// Extracting the elements of all the inner arrays into one array.
var allElements = [];
for(var arr of myArray) {
    for(var ele of arr) {
        allElements.push(ele);
    }
}

// Updating the lengths of first and last inner arrays based on your requirement.
var firstArrLen = 2;
var lastArrLen = lengths[lengths.length -1]   (lengths[0] - 2)
lengths[0] = firstArrLen;
lengths[lengths.length -1] = lastArrLen;

// Initializing the final/result array.
var finalArr = [];

// Adding/Pushing the new inner arrays into the finalArr
for(var len of lengths) {
    var tempArr = [];
    for(var i=0; i<len; i  ) {
        tempArr.push(allElements[i]);
    }
    finalArr.push(tempArr);
    for(var i=0; i<len; i  ) {
        // removes the first element from the array.
        allElements.shift();
    }
}

CodePudding user response:

The requirements were not that clear and I don't know why you would do any of that but here you have your solution: I have written a function that you can use to limit the cardinality of the subArrays.

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

function reorderArray(arr) {
    let buff = [];
    let newArr = [];
    let maxSubarrCardinality = 2;

    //flatMapping second level elements
    //in a single level buffer
    for (subArr of arr) {
        for (elem of subArr) {
            buff.push(elem);
        }
    }

    //Inserting elements one at the time
    //into a new array
    for (elem in buff) {

        //when the new array is empty
        //push in the new array the first empty subArray
        if (newArr.at(-1) == undefined)
            newArr.push([]);

        //if the last subArray has reached
        //the maxCardinality push a new subArray
        else if (newArr.at(-1).length >= maxSubarrCardinality) {
            newArr.push([]);
            newArr.at(-1).push(elem);
        }
        //if none of the previous special cases
        //just add the element to the last subArray of the newArray
        else {
            newArr.at(-1).push(elem);
        }
    }
    return newArr;
}

myArray = reorderArray(myArray);

CodePudding user response:

Steps


I used Array#flat, so I had to keep track of the indices and length of each item.

let i = 0;
let itemLength = array[0]?.length;

After flattening the array, I use Array#reduce to loop through the items, setting the initialValue to an empty array.

I get the last item in the array and check if its length has reached the maximum allowed (which should be the one set in the rules argument for that index or the size argument).

If the max hasn't been reached, I push the current item into the last array. If it has, I create a new array, with the item as the only element

array.flat().reduce((acc, cur) => {
  if (acc.length === 0) acc.push([]); // Just for the first iteration

  if (acc.at(-1).length < (rules[i] ?? size)) acc[acc.length - 1].push(cur);
  else acc.push([cur]);

If then either decrement the value of itemLength, or set it to the length of the next array. and increment the i variable to the next index

itemLength = itemLength === 0 ? (array[  i] ?? []).length : --itemLength;

let array = [[1, 2, 3, 4], [5, 6], [7, 8, 9], [10]];

function conditionalChunk(array, size, rules = {}) {
  let i = 0;
  let itemLength = array[0]?.length;
  
  return array.flat().reduce((acc, cur) => {
    if (acc.length === 0) acc.push([]); // Just for the first iteration

    if (acc.at(-1).length < (rules[i] ?? size)) acc[acc.length - 1].push(cur);
    else acc.push([cur])
    
    itemLength = itemLength === 0 ? (array[  i] ?? []).length : --itemLength;
    return acc;
  }, []);
}

console.log(JSON.stringify(conditionalChunk(array, 3, { 0: 2 })));

  • Related