Home > Back-end >  Deep flatten array fields in object
Deep flatten array fields in object

Time:03-19

I have an object which has some fields that are arrays (either of strings or of other objects), I am trying to convert this object into a csv however for the case of having arrays, I want the csv to go vertically in case of arrays (instead of horizontal with the index appended to the field name). After trying several npm libraries and online converters, I couldn't achieve what I wanted, the fields with arrays were simply written with their indices as column names.

As a workaround I am trying now to flatten the object to flesh out the array fields and then convert it to csv, but the flattening still kept the arrays as is with no change to the number of objects in the output. I tried libraries such as lodash, underscore, Array's flat, nothing worked.

Is there a way to achieve this either by directly converting to csv or at least flattening the object.

The object sample that I have is below

    [
        {
            "field1": "Hello",
            "field2": [
                "list item 1",
                "list item 2",
                "list item 3"
            ],
            "field3": [],
            "field4": [{
                "subfield1": "World",
                "subfield2": "!"
            }, {
                "subfield1": "Again",
                "subfield2": "?"
            }]
        }
    ]

Based on this sample object, my output should be.

[
    {
        "field1": "Hello",
        "field2": "list item 1",
        "field3": null, // or [], in this case it wouldn't matter
        "field4": {
            "subfield1": "World",
            "subfield2": "!"
        }
    },
    {
        "field1": "Hello",
        "field2": "list item 1",
        "field3": null,
        "field4": {
            "subfield1": "Again",
            "subfield2": "?"
        }
    },
    {
        "field1": "Hello",
        "field2": "list item 2",
        "field3": null,
        "field4": {
            "subfield1": "World",
            "subfield2": "!"
        }
    },
    {
        "field1": "Hello",
        "field2": "list item 2",
        "field3": null,
        "field4": {
            "subfield1": "Again",
            "subfield2": "?"
        }
    },
    {
        "field1": "Hello",
        "field2": "list item 3",
        "field3": null,
        "field4": {
            "subfield1": "World",
            "subfield2": "!"
        }
    },
    {
        "field1": "Hello",
        "field2": "list item 3",
        "field3": null,
        "field4": {
            "subfield1": "Again",
            "subfield2": "?"
        }
    }
]

Is there some library that I can use to achieve this?

CodePudding user response:

You could take a cartesian product for all values, except empty arrays.

function getCartesian(object) {
    return Object.entries(object).reduce((r, [k, v]) => {
        const temp = [];
        if (Array.isArray(v) && !v.length) v = null;
        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;
    }, [{}]);
}

const
    data = { field1: "Hello", field2: ["list item 1", "list item 2", "list item 3"], field3: [], field4: [{ subfield1: "World", subfield2: "!" }, { subfield1: "Again", subfield2: "?" }] },
    result = getCartesian(data);

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

  • Related