3

I'm using Lodash to convert one JSON structure into another. I need to form all combinations of two arrays and marry-up each combination with a data value taken from a third array.

How do I generate all combinations and extract the right data-item for each?

Source JSON structure:

{
    "regimes"      :   [ "AA", "BB" ],
    "axes"         :   [ "Horizontal", "Vertical" ],
    "data-items"   :   [ 1, 2, 3, 4 ]
}


Destination JSON structure:

[
    {
        "regime"      : "AA",
        "axis"        : "Horizontal",
        "data-item"   : 1
    },
    {
        "regime"      : "AA",
        "axis"        : "Vertical",
        "data-item"   : 2
    },
    {
        "regime"      : "BB",
        "axis"        : "Horizontal",
        "data-item"   : 3
    },
    {
        "regime"      : "BB",
        "axis"        : "Vertical",
        "data-item"   : 4
    }
] 
CodeCabbie
  • 3,098
  • 2
  • 19
  • 30
  • do not you need, `{"regime" : "AA", "axis" : "Horizontal", "data-item" : 3}` and 4? – marmeladze May 18 '17 at 11:10
  • No. I'm **not** looking for all combinations of all three arrays. Rather, all combinations of the first two, and then associate each combination with a data-item taken **in order** from the third array. It's a bit counter intuitive! - I've double checked the JSON above and it is exactly as I need. – CodeCabbie May 18 '17 at 11:13

2 Answers2

2

I've came up with that hybrid and ugly solution. Maybe you can refactor it.

What I'm going to do is,

1) to take cartesian product of, a["regimes"] and a["axes"] which will give you,

[ "AA", "Horizontal" ] 
[ "AA", "Vertical" ] 
[ "BB", "Horizontal" ] 
[ "BB", "Vertical" ]

2) then, slice a["data-items"] to

first = [1,2]
last = [3,4]

3) and zip,

[[ "AA", "Horizontal" ],[ "AA", "Vertical" ]]

with first = [1,2]

and

[[ "BB", "Horizontal" ],[ "BB", "Vertical" ]]

with last. which will give us

[[ "AA", "Horizontal" ], 1]
[[ "AA", "Vertical" ],2]
[[ "BB", "Horizontal" ],3]
[[ "BB", "Vertical" ],4]

lastly we can easily call map on above array of arrays

above_multidimensional_array.map(e=>_.flatten(e))


_.zip(cartesianProductOf(a.regimes, a.axes)
  .slice(0,2), a["data-items"]
  .slice(0,2))
  .map(e=>_.flatten(e)
).concat(
  _.zip(cartesianProductOf(a.regimes, a.axes)
    .slice(2,4), a["data-items"]
    .slice(2,4))
    .map(e=>_.flatten(e))
).map(e=>({'regime': e[0], 'axis': e[1], 'data-item': e[2]}))

result:

[
    { regime: "AA", axis: "Horizontal", data-item: 1 } 
    { regime: "AA", axis: "Vertical", data-item: 2 } 
    { regime: "BB", axis: "Horizontal", data-item: 3 } 
    { regime: "BB", axis: "Vertical", data-item: 4 }
]

cartesian product implementations.

#https://gist.github.com/ijy/6094414#file-cartesian-product-js
function cartesianProductOf() {
    return _.reduce(arguments, function(a, b) {
        return _.flatten(_.map(a, function(x) {
            return _.map(b, function(y) {
                return x.concat([y]);
            });
        }), true);
    }, [ [] ]);
};

#https://gist.github.com/FestivalBobcats/1323387
function cartesianProductOf(){
    return _.reduce(arguments, function(mtrx, vals){
        return _.reduce(vals, function(array, val){
            return array.concat(
                _.map(mtrx, function(row){ return row.concat(val); })
            );
        }, []);
    }, [[]]);
}

Cartesian product of multiple arrays in JavaScript

Community
  • 1
  • 1
marmeladze
  • 6,468
  • 3
  • 24
  • 45
1

This works well: (where x = source json)

Step 1. Get the DOT product of regimes and axes

    DOT = _(x.regimes)
        .map((r)  => {
            return x.axes.map((a)=> {
                return {
                    regime: r,
                    axis: a
                }
            })
        })
        .flatten()


Step 2. Get the data values

    data = _(x.data)
        .map((v)  => {
            return {data:v};
            }
        )
        .value()


Step 3. Merge the two

    // Merge the two collections

    result = _(DOT).merge(data)

Job done.

CodeCabbie
  • 3,098
  • 2
  • 19
  • 30