2

So I have this array

var mapped = [[2016, "October", "Monday", {object}], [2017, "January", "Friday", {object}], [2017, "January", "Wednesday", {object}], [2017, "October", "Monday", {object}]]

What I want to accomplish is something like this:

[{
    "2016": [{
        "October": [{
            "Monday": [{object}]
        }]
    }],
}, {
    "2017": [{
        "January": [{
            "Friday": [{object}]
        }, {
            "Wednesday": [{object}]
        }]
    }, {
        "October": [{
            "Monday": [{object}]
        }]
    }]
}]

I've been searching around for so long, and I can't find a solution.. By using reduce, I'm getting something like this:

[
    2016: [{
        "month": "October"
    }]
],
[
    2017: [{
        "month": "January"
    },
    {
        "month": "January"
    },
    {
        "month": "September"
    }]
]

So it seems like I'm into something, but still so far away... This is what I'm doing:

mapped.reduce((years, array) => {

                    years[array[0]] = years[array[0]] || [];

                    years[array[0]].push({
                        month: array[1]
                    })

                    return years;

                }, [])

2 Answers 2

3

Not exactly what you specified, but I feel the following script outputs a format that will be most useful -- it only produces arrays at the deepest level:

const  mapped = [[2016, "October", "Monday", { a: 1 }], [2017, "January", "Friday", { a: 1 }], [2017, "January", "Wednesday", { a: 1 }], [2017, "October", "Monday", { a: 1 }]];
   
const result = mapped.reduce( (acc, [year, month, day, object]) => {
    let curr = acc[year] = acc[year] || {};
    curr = curr[month] = curr[month] || {};
    curr = curr[day] = curr[day] || [];
    curr.push(object);
    return acc;
}, {});

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

With array wrapping

If you really need the wrapping arrays, you can apply an extra recursive function to the previous result:

const  mapped = [[2016, "October", "Monday", { a: 1 }], [2017, "January", "Friday", { a: 1 }], [2017, "January", "Wednesday", { a: 1 }], [2017, "October", "Monday", { a: 1 }]];
   
const result = mapped.reduce( (acc, [year, month, day, object]) => {
    let curr = acc[year] = acc[year] || {};
    curr = curr[month] = curr[month] || {};
    curr = curr[day] = curr[day] || [];
    curr.push(object);
    return acc;
}, {});

function wrapInArrays(data) {
    return Array.isArray(data) ? data 
        : Object.entries(data).map ( ([key, value]) => {
            return { [key]: wrapInArrays(value) };
        });
}

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

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

1 Comment

You sir, are goddamn amazing. I've learned a lot from this answer. Thank you so much.
0

To achieve the same exact structure you can try the strategy below. This will work upto any level of nesting and will continue to build the nested object. Please have a look at the example to see various levels of nesting which will be handled generically.

  • Map each element into the corresponding nested structure (Map with reduce)

  • Combine each element from mapped array into a single object to merge all redundant keys

  • Convert the final nested object into the desired array structure.

const mapped = [[2016, "October", "Monday", "Morning", {time: "10AM"}], [2017, "January", "Friday", {object: "OBJECT"}], [2017, "January", "Wednesday", {object: "OBJECT"}], [2017, "October", "Monday", {object: "OBJECT"}]];

// Map all objects to the respective nested structure
const nestedMap = mapped.map(elem => {
  let reversed = [...elem.reverse()];
  let firstElem = reversed.splice(0, 1)[0];
  return reversed.reduce((acc, elem) => {let newAcc = {}; newAcc[elem] = [acc]; return {...newAcc}}, firstElem);
})

// Combine array to form a single object
const nestedObj = nestedMap.reduce((acc, elem) => {
  let firstKey = Object.keys(elem)[0];
  acc[firstKey]
    ?
    acc[firstKey].push(elem[firstKey][0])
    :
    acc[firstKey] = elem[firstKey];
  return acc;
}, {})

// Convert back into the array with each object as element
const nestedFinalArr = Object.keys(nestedObj).map(key => ({[key]: nestedObj[key]}))

console.log(nestedFinalArr);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.