Search code examples
javascriptarraysjavascript-objectscartesian-product

Cartesian product of javascript object with different types of values like string, object and array


I am working on an assignment. I have the following object form.

{
    name: "name here",
    skills:  [ "cash", "shares" ],
    subjects: 
    [ 
      {
        subName: "subject1",
            remark: ['remark1', 'remark2']
          },
      {
        subName: "subject2",
            remark: ['remark1', 'Hockey']
          }
    ]
}

I want to generate a Cartesian product of the properties so that the output is an array of the following form:

[
   { "name": "name here",  "skills":  "cash",   "subjects": {  "subName":    "subject1", “remark”: “remark2” }},
   { "name": "name here",  "skills":  "cash",   "subjects": {  "subName":    "subject1", “remark”: “remark1”  }},
   { "name": "name here",  "skills":  "cash",   "subjects": {  "subName":    "subject2", “remark”: “remark1” }},
   { "name": "name here",  "skills":  "cash",   "subjects": {  "subName":    "subject2",  “remark”: “Hockey” }},
   { "name": "name here",  "skills":  "shares",  "subjects": {  "subName":  "subject1",  “remark”: “remark1” }},
   { "name": "name here",  "skills":  "shares",  "subjects": {  "subName":   "subject1",  “remark”: “remark2” }},
   { "name": "name here",  "skills":  "shares",  "subjects": {  "subName":  "subject2",  “remark”: “remark1”   }},
   { "name": "name here",  "skills":  "shares",  "subjects": {  "subName":  "subject2",  “remark”: “Hockey”  }}
]

I have tried many of the algorithms(mentioned in other SO posts) and even tried to customize some of them, but still not much improvement.

I would really appreciate any kind of help in this. Thanks in advance for your help.


Solution

  • You could take a recursive function which separates all key/value pairs and build a new cartesian product by iterating the values, if an array with objects call getCartesian again and build new objects.

    The referenced link does not work, because of the given arrays of objects which the linked answer does not respect.

    function getCartesian(object) {
        return Object.entries(object).reduce((r, [k, v]) => {
            var temp = [];
            r.forEach(s =>
                (Array.isArray(v) ? v : [v]).forEach(w =>
                    (w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
                        temp.push(Object.assign({}, s, { [k]: x }))
                    )
                )
            );
            return temp;
        }, [{}]);
    }
    
    var data = { name: "name here", skills: ["cash", "shares"], subjects: [{ subName: "subject1", remark: ['remark1', 'remark2'] }, { subName: "subject2", remark: ['remark1', 'Hockey'] }] };
    
    console.log(getCartesian(data));
    .as-console-wrapper { max-height: 100% !important; top: 0; }