简体   繁体   中英

Transform array of objects using Javascript and Underscore.js

Assuming I have the following list:

var products = [
    {"id": 6, "name": "product6", "category": "category2", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 5, "name": "product5", "category": "category2", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 7, "name": "product7", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 1, "name": "product1", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 3, "name": "product3", "category": "category2", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 8, "name": "product8", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 2, "name": "product2", "category": "category3", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
    {"id": 4, "name": "product4", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3}
] 

How would I then turn it into something like this using javascript and "ideally underscore.js groupBy? (or considering the table layout below, have you got any idea how to include the months here also?). As I see it the below nested structure would get me "almost" there.

var hierarchicalList = [
    { 
        "id": -1, // something unique I guess?
        "name": "category1", 
        "1": 216, // aggregate number of sales per week for all children
        "2": 148, 
        "3": 256, 
        "4": 24, 
        "5": 184, 
        "6": 128, 
        "7": 12,
        "children": [
            {
                "id": 7, 
                "name": "product7", 
                "1": 54, 
                "2": 37, 
                "3": 64, 
                "4":6, 
                "5": 46, 
                "6": 32, 
                "7": 3
            }
            {
                "id": 1, 
                "name": "product1", 
                "1": 54, 
                "2": 37, 
                "3": 64, 
                "4":6, 
                "5": 46, 
                "6": 32, 
                "7": 3
            }
        ]
    }, 
    { 
        "id": -2, 
        "name": "category2",  
        "1": 162, 
        "2": 111, 
        ...
        "7": 9,
        "children": [
            // product6, 5, 3
        ]
    }
]

I'm going to use this for "row grouping" on product category in a table, where I'm looking to plug my datastructure in a react grid component like Griddle So to summarize, in my case how would I:

  • get the aggregated sales per category per week from the underscore groupBy category result?

https://jsfiddle.net/zt62a3Lc/

Well. Here's a potential solution. It might not use _.groupBy, but IMO if you forced yourself down that path you might be trying to solve the problem with hands tied behind your back.

var categoryGraft = {};
products.forEach(function (product) {
    var key = product.category;
    if (typeof categoryGraft[key] === 'undefined') {
        categoryGraft[key] = {
            "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "6": 0, "7": 0,
            "name": key,
            "children": []
        };
    }

    categoryGraft[key]["1"] += product["1"];
    categoryGraft[key]["2"] += product["2"];
    categoryGraft[key]["3"] += product["3"];
    categoryGraft[key]["4"] += product["4"];
    categoryGraft[key]["5"] += product["5"];
    categoryGraft[key]["6"] += product["6"];
    categoryGraft[key]["7"] += product["7"];

    // delete from original or clone...
    delete product.category;
    categoryGraft[key].children.push(product);
});

var hierarchicalList = [];
var key, category;
for (key in categoryGraft) {
    category = categoryGraft[key];
    hierarchicalList.push(category);
}

Here's my solution using _.chain()

It's not restricted to 1 to 7 and works with any number of numeric properties. Moreover it is a functional solution without mutating any variable.

    var products = [
        {"id": 6, "name": "product6", "category": "category2", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 5, "name": "product5", "category": "category2", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 7, "name": "product7", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 1, "name": "product1", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 3, "name": "product3", "category": "category2", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 8, "name": "product8", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 2, "name": "product2", "category": "category3", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3},
        {"id": 4, "name": "product4", "category": "category1", "1": 54, "2": 37, "3": 64, "4":6, "5": 46, "6": 32, "7": 3}
    ] 

    // null coalescing helper
    var coal = (a, b) => a != null ? a : b

    _.chain(products)
    // make an object: {category1: [...], category2: [...], ...}
    .groupBy(c => c.category)
    .mapObject((val, key) =>
        _.chain(val)
        .reduce(
            ((a, b) =>
                _.chain(_.chain(a).keys().union(_.keys(b)).value())
                .filter(k => !_(['name', 'id']).contains(k))
                .map(k =>
                    [k, !isNaN(parseInt(k)) ? coal(a[k], 0) + coal(b[k], 0) : coal(a[k], b[k])]
                )
                .concat([["children", _(a.children).concat(b)]])
                .object()
                .value()

            ), {children: []}
        )
        .value()
    )
    // convert the object into a list of pairs [["category1", {...}], ["category2", {...}], ...]
    .pairs()
    .map((d, i) => 
        // d is a pair: ["category1", {...}]
        _.extend(d[1], {name: d[0], id: (i+1) * -1}) // make the id
    )
    .value()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM