Home > Net >  Group array of strings in to object containing nested arrays
Group array of strings in to object containing nested arrays

Time:09-24

I would be grateful if someone could help me get unstuck. I have an array which I would like to describe using an object. The array looks like this:

const numberGroupArray = [
 'GROUP_A',
 'ONE',
 'TWO',
 'BREAK',
 'FOUR',
 'GROUP_B',
 'SIX',
 'GROUP_C',
 'EIGHT',
 'BREAK',
 'TEN',
 'ELEVEN',
 'GROUP_D',
 'THIRTEEN',
 'BREAK',
 'FIFTEEN',
 'BREAK',
 'SEVENTEEN',
 'EIGHTEEN',
 'NINETEEN',
]

And the goal object looks like this:

const numberInGroup = {
  GROUP_A: [[1, 2], [4]],
  GROUP_B: [[6]],
  GROUP_C: [[8], [10, 11]],
  GROUP_D: [[13], [15], [17, 18, 19]],
};

Where each number refers to an index from the array above. numberInGroup.GROUP_A[0][1] refers to 'TWO' in the array above. Similarly, numberInGroup.GROUP_D[2][1] refers to 'SEVENTEEN'.

Attempting to work through the creation of the object:

  1. 'GROUP_A' is set
  2. A working array is created and strings 'ONE' and 'TWO' are pushed to 'GROUP_A'.
  3. A 'BREAK' creates a new working array and 'FOUR' is pushed to 'GROUP_A'.
  4. 'GROUP_B' is set and steps 2 and 3 repeat for the rest of the initial array.

If you need more info, happy to provide. Thank you in advance.

CodePudding user response:

I would reduce the array by keeping a closure over the last group.

const
    data = ['GROUP_A', 'ONE', 'TWO', 'BREAK', 'FOUR', 'GROUP_B', 'SIX', 'GROUP_C', 'EIGHT', 'BREAK', 'TEN', 'ELEVEN', 'GROUP_D', 'THIRTEEN', 'BREAK', 'FIFTEEN', 'BREAK', 'SEVENTEEN', 'EIGHTEEN', 'NINETEEN'],
    result = data.reduce((group => (r, v) => {
        if (v.startsWith('GROUP_')) {
            group = r[v] = [[]];
            return r;
        }
        if (v === 'BREAK')  {
            group.push([]);
            return r;
        }
        group[group.length - 1].push(v);
        return r;
    })(), {});

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

Simply loop over the array and build the result as you go along.

Basically, if you see GROUP_A (or whatever) then you create a new property in your result, with a blank array. Keep track of the current group and which array you are pushing into.

Then when you hit BREAK, add a new array and shift the counter.

For values, use your counters and place the value in the right spot.

const numberGroupArray = [
  'GROUP_A',
  'ONE',
  'TWO',
  'BREAK',
  'FOUR',
  'GROUP_B',
  'SIX',
  'GROUP_C',
  'EIGHT',
  'BREAK',
  'TEN',
  'ELEVEN',
  'GROUP_D',
  'THIRTEEN',
  'BREAK',
  'FIFTEEN',
  'BREAK',
  'SEVENTEEN',
  'EIGHTEEN',
  'NINETEEN',
];

let numberInGroup = {},  // The result object
    currGroup,  // Which group/property are we inside?
    currIdx,  // Which sub-array are we pushing to?
    isGroup;  // Do we need to change to a new group?

numberGroupArray.forEach(val => {
    // Is this a new group?
    // If so, then make a new property and reset the counters
    if ((isGroup = val.match(/GROUP_[A-Z]/))) {
        currGroup = isGroup[0];
        currIdx = 0;

        numberInGroup[currGroup] = [[]];
    }
    // BREAK means to push a new array into the current group
    else if (val === 'BREAK') {
        currIdx  ;
        numberInGroup[currGroup].push([]);
    }
    // Otherwise push the value into the right spot in the final result
    else {
        numberInGroup[currGroup][currIdx].push(val);
    }
});

console.log(numberInGroup);

  • Related