1

Suppose I have the following JSON array:

[
    {
        "MainCategory": "1",
        "SubCategory": "a",
        "Value": "val1"
    },
    {
        "MainCategory": "1",
        "SubCategory": "a",
        "Value": "val2"
    },
    {
        "MainCategory": "1",
        "SubCategory": "b",
        "Value": "val3"
    },
    {
        "MainCategory": "2",
        "SubCategory": "a",
        "Value": "val4"
    },
    {
        "MainCategory": "2",
        "SubCategory": "b",
        "Value": "val5"
    },
    {
        "MainCategory": "2",
        "SubCategory": "b",
        "Value": "val6"
    }
]

And would like to convert it into the following multidimensional object in JavaScript (no Lodash):

{
    "1":{
        "a": [
            "val1",
            "val2"
        ],
        "b": [
            "val3"
        ]
    },
    "2":{
        "a": [
            "val4"
        ],
        "b": [
            "val5",
            "val6"
        ]
    }
}

I figure I can do it with a foreach, but I'm trying to do it using the reduce function (HOPING that is the right one to use here) and just not getting the right syntax.

My current GUESS (not working) is something along the lines of:

const newJson = CurrentJson.reduce((result, {MainCategory, SubCategory, Value}) => {
    (result[MainCategory][SubCategory] = result[MainCategory][SubCategory] || [])
    .push(Value);

    return result;
}, {});

How can I do this?

2 Answers 2

1

You may use reduce as follows;

var data = [ { "MainCategory": "1"
             , "SubCategory": "a"
             , "Value": "val1"
             }
           , { "MainCategory": "1"
             , "SubCategory": "a"
             , "Value": "val2"
             }
           , { "MainCategory": "1"
             , "SubCategory": "b"
             , "Value": "val3"
             }
           , { "MainCategory": "2"
             , "SubCategory": "a"
             , "Value": "val4"
             }
           , { "MainCategory": "2"
             , "SubCategory": "b"
             , "Value": "val5"
             }
           , { "MainCategory": "2"
             , "SubCategory": "b"
             , "Value": "val6"
             }
           ],
   res  = data.reduce((r,o) => ( r[o.MainCategory] ? r[o.MainCategory][o.SubCategory] ? r[o.MainCategory][o.SubCategory].push(o.Value)
                                                                                      : r[o.MainCategory][o.SubCategory] = [o.Value]
                                                   : r[o.MainCategory] = {[o.SubCategory]: [o.Value]}
                               , r
                               ) ,{});
  console.log(res);

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

7 Comments

All I can say is OMFG!!! - I'm going to have to read, re-read and, then, dissect this for hours to come, but WOW!!!! Truly, thank you SO MUCH!!!!
While this does work, it's not the most readable code
@Cjmarkham I have to agree and not agree at the same time. It depends on who is reading. To me ternary alongside comma operator and wide indenting forms the most readable JS code. I suppose it's a matter of eyes getting used to.
It's the ternary depth that I though could be a bit troublesome to understand most, although I've never seem commas placed like that, each to their own
@JohnBustos Exactly. It's saving you from using return keyword.
|
1

You can use a reducer to iterate over the original JSON and build up the new object.

const json = [
    {
        "MainCategory": "1",
        "SubCategory": "a",
        "Value": "val1"
    },
    {
        "MainCategory": "1",
        "SubCategory": "a",
        "Value": "val2"
    },
    {
        "MainCategory": "1",
        "SubCategory": "b",
        "Value": "val3"
    },
    {
        "MainCategory": "2",
        "SubCategory": "a",
        "Value": "val4"
    },
    {
        "MainCategory": "2",
        "SubCategory": "b",
        "Value": "val5"
    },
    {
        "MainCategory": "2",
        "SubCategory": "b",
        "Value": "val6"
    }
]

const newJson = json.reduce((prev, curr) => {
  // Check for the MainCategory first
  if (prev[curr.MainCategory] === undefined) {
    prev[curr.MainCategory] = {
      [curr.SubCategory]: [] // Add the SubCategory key and define as empty array
    }
  }
  
  // Check if we have the SubCategory
  if (prev[curr.MainCategory][curr.SubCategory] === undefined) {
    prev[curr.MainCategory][curr.SubCategory] = [] // define as empty array
  }

  // Push the Value
  prev[curr.MainCategory][curr.SubCategory].push(curr.Value)
  
  return prev
}, {})

console.log(newJson)

1 Comment

Just as beautiful a solution and, as you said, much more readable, I actually understood the compact version, but this makes for an amazing answer, though, to include for others that may not. Thank you!!!

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.