0

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?

3
  • if input is [[1, 2, 3, 4], [5, 6], [7, 8, 9], [10]]; Output should be [ [1,2] [3,4] [5,6] [7,8] [9,10] ] is that correct ? Commented Sep 21, 2021 at 21:53
  • no, output should be: [[1, 2], [3,4], [5,6,7], [8,9,10]]; because you can see that in original array myArray[0][2] contain 3 elements, so it need to keep 3 elements Commented Sep 21, 2021 at 21:55
  • Why rules is an object and not an array? Can it skip indices, like {0:2, 3:1}? I think you, and also the answers posted so far, could make use of developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Sep 21, 2021 at 23:11

3 Answers 3

1

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

Sign up to request clarification or add additional context in comments.

Comments

1

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

6 Comments

If I run console.log(JSON.stringify(conditionalChunk(array, 4, { 0: 2 }))); then array[2] change number of elements but 4 means that only new added array to group can contain max 4 elements... array[2] need to stay with the same number of elements (3)
What do you expect to be the result if size is 4 and rules is still { 0: 2 }? Is it [[1, 2], [3, 4], [5, 6, 7, 8], [9, 10]]?
If it's the length of the initial item at the index that should be the max, where is the size argument supposed to be used and what will it be used for?? @AleksPer
Do you expect the result if size is 4 and rules is still { 0: 2 } to be [[1,2],[3,4],[5,6],[7,8,9],[10]]?
I expect: [[1,2],[3,4],[5,6,7],[8,9,10]]
|
1

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 = [];
myArray.forEach((arr) => {lengths.push(arr.length);});

// Extracting the elements of all the inner arrays into one array.
var allElements = [].concat.apply([], myArray);

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

console.log(finalArr);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.