javascript减少了数组中对象的多个键

时间:2022-05-25 18:22:34

I have have map of Object of the following type (example data below)

我有以下类型的Object映射(下面的示例数据)

{[date:string]:Array<{[type:string]:{amount:number, price:number}}>}

And I need to reduce the array to a single object of amount sum and price averaged

我需要将数组减少到金额总和和平均价格的单个对象

I have read a couple of post on how to reduce data over an object like

我已经阅读了几篇关于如何通过像这样的对象减少数据的帖子

How to map and reduce over an array of objects?

如何映射和减少一组对象?

Javascript reduce on array of objects

Javascript减少了对象数组

In my case the "type" is a ENUM of ["PV","BHKW","FALLBACK"] but it could be extended. Apart from writing declarative for in loops, i can't figure out how to use array.reduce to accomplish this more elegantly.

在我的情况下,“类型”是[“PV”,“BHKW”,“FALLBACK”]的ENUM,但它可以扩展。除了为in循环编写声明之外,我无法弄清楚如何使用array.reduce来更优雅地完成它。

Any suggestions?

{
    "2018-08-01T11:00:00+02:00": [
        {
            "BHKW": {
                "amount": 131,
                "price": 85
            },
            "FALLBACK": {
                "amount": 84,
                "price": 1
            }
        },
        {
            "BHKW": {
                "amount": 307,
                "price": 58
            },
            "PV": {
                "amount": 4,
                "price": 60
            }
        }
    ],
    "2018-08-01T12:00:00+02:00": [
        {
            "BHKW": {
                "amount": 288,
                "price": 59
            },
            "PV": {
                "amount": 742,
                "price": 73
            }
        },
        {
            "BHKW": {
                "amount": 250,
                "price": 49
            },
            "PV": {
                "amount": 507,
                "price": 98
            }
        },
        {
            "PV": {
                "amount": 368,
                "price": 22
            },
            "BHKW": {
                "amount": 357,
                "price": 73
            }
        },
        {
            "FALLBACK": {
                "amount": 135,
                "price": 62
            },
            "BHKW": {
                "amount": 129,
                "price": 93
            }
        }
    ],

3 个解决方案

#1


2  

You can use lodash#mapValues to transform each value of the object data object. To combine all objects with the same key values, you can use lodash#mergeWith with the callback testing if the keys being transformed will be evaluated.

您可以使用lodash#mapValues转换对象数据对象的每个值。要将所有对象与相同的键值组合在一起,您可以将lodash#mergeWith与回调测试一起使用,以便评估要转换的键。

const result = _.mapValues(data, collection => 
  _.mergeWith({}, ...collection, (a = 0, b = 0, key) =>
    ['amount', 'price'].includes(key)
      ? a + b
      : void 0 // is equivalent to undefined to retain current value
  ));

const data = {
    "2018-08-01T11:00:00+02:00": [
        {
            "BHKW": {
                "amount": 131,
                "price": 85
            },
            "FALLBACK": {
                "amount": 84,
                "price": 1
            }
        },
        {
            "BHKW": {
                "amount": 307,
                "price": 58
            },
            "PV": {
                "amount": 4,
                "price": 60
            }
        }
    ],
    "2018-08-01T12:00:00+02:00": [
        {
            "BHKW": {
                "amount": 288,
                "price": 59
            },
            "PV": {
                "amount": 742,
                "price": 73
            }
        },
        {
            "BHKW": {
                "amount": 250,
                "price": 49
            },
            "PV": {
                "amount": 507,
                "price": 98
            }
        },
        {
            "PV": {
                "amount": 368,
                "price": 22
            },
            "BHKW": {
                "amount": 357,
                "price": 73
            }
        },
        {
            "FALLBACK": {
                "amount": 135,
                "price": 62
            },
            "BHKW": {
                "amount": 129,
                "price": 93
            }
        }
    ]
};

const result = _.mapValues(data, collection => 
  _.mergeWith({}, ...collection, (a = 0, b = 0, key) =>
    ['amount', 'price'].includes(key)
      ? a + b
      : void 0 // is equivalent to undefined to retain current value
  ));
  
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

#2


1  

solved it!

var x = _.reduce(
    list,
    (acc, item) => {
        for (const key in item) {
            if (!acc[key]) {
                acc[key] = { price: 0, amount: 0 };
            }

            if (item[key] && item[key].price) {
                acc[key].price += item[key].price;
            }

            if (item[key] && item[key].amount) {
                acc[key].amount += item[key].amount;
            }
        }
        return acc;
    },
    {}
);

#3


0  

Another way (although not as elegant as the _.merge approach already posted) is with _.mapValues/_.reduce/_.assignWith or _.extendWith:

另一种方式(尽管不像已经发布的_.merge方法那样优雅)是_.mapValues / _.reduce / _.assignmentWith或_.extendWith:

var data = { "2018-08-01T11:00:00+02:00": [{ "BHKW": { "amount": 131, "price": 85 }, "FALLBACK": { "amount": 84, "price": 1 } }, { "BHKW": { "amount": 307, "price": 58 }, "PV": { "amount": 4, "price": 60 } } ], "2018-08-01T12:00:00+02:00": [{ "BHKW": { "amount": 288, "price": 59 }, "PV": { "amount": 742, "price": 73 } }, { "BHKW": { "amount": 250, "price": 49 }, "PV": { "amount": 507, "price": 98 } }, { "PV": { "amount": 368, "price": 22 }, "BHKW": { "amount": 357, "price": 73 } }, { "FALLBACK": { "amount": 135, "price": 62 }, "BHKW": { "amount": 129, "price": 93 } } ] }

var result =
  _.mapValues(data, (x) =>
    _.reduce(x, (r, c) =>
      _.assignWith(r, c, (o, s) =>
        o && s ? ({ amount: o.amount + s.amount, price: o.price + s.price }) : {...o, ...s})
    )
  )

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

#1


2  

You can use lodash#mapValues to transform each value of the object data object. To combine all objects with the same key values, you can use lodash#mergeWith with the callback testing if the keys being transformed will be evaluated.

您可以使用lodash#mapValues转换对象数据对象的每个值。要将所有对象与相同的键值组合在一起,您可以将lodash#mergeWith与回调测试一起使用,以便评估要转换的键。

const result = _.mapValues(data, collection => 
  _.mergeWith({}, ...collection, (a = 0, b = 0, key) =>
    ['amount', 'price'].includes(key)
      ? a + b
      : void 0 // is equivalent to undefined to retain current value
  ));

const data = {
    "2018-08-01T11:00:00+02:00": [
        {
            "BHKW": {
                "amount": 131,
                "price": 85
            },
            "FALLBACK": {
                "amount": 84,
                "price": 1
            }
        },
        {
            "BHKW": {
                "amount": 307,
                "price": 58
            },
            "PV": {
                "amount": 4,
                "price": 60
            }
        }
    ],
    "2018-08-01T12:00:00+02:00": [
        {
            "BHKW": {
                "amount": 288,
                "price": 59
            },
            "PV": {
                "amount": 742,
                "price": 73
            }
        },
        {
            "BHKW": {
                "amount": 250,
                "price": 49
            },
            "PV": {
                "amount": 507,
                "price": 98
            }
        },
        {
            "PV": {
                "amount": 368,
                "price": 22
            },
            "BHKW": {
                "amount": 357,
                "price": 73
            }
        },
        {
            "FALLBACK": {
                "amount": 135,
                "price": 62
            },
            "BHKW": {
                "amount": 129,
                "price": 93
            }
        }
    ]
};

const result = _.mapValues(data, collection => 
  _.mergeWith({}, ...collection, (a = 0, b = 0, key) =>
    ['amount', 'price'].includes(key)
      ? a + b
      : void 0 // is equivalent to undefined to retain current value
  ));
  
console.log(result);
.as-console-wrapper{min-height:100%;top:0}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

#2


1  

solved it!

var x = _.reduce(
    list,
    (acc, item) => {
        for (const key in item) {
            if (!acc[key]) {
                acc[key] = { price: 0, amount: 0 };
            }

            if (item[key] && item[key].price) {
                acc[key].price += item[key].price;
            }

            if (item[key] && item[key].amount) {
                acc[key].amount += item[key].amount;
            }
        }
        return acc;
    },
    {}
);

#3


0  

Another way (although not as elegant as the _.merge approach already posted) is with _.mapValues/_.reduce/_.assignWith or _.extendWith:

另一种方式(尽管不像已经发布的_.merge方法那样优雅)是_.mapValues / _.reduce / _.assignmentWith或_.extendWith:

var data = { "2018-08-01T11:00:00+02:00": [{ "BHKW": { "amount": 131, "price": 85 }, "FALLBACK": { "amount": 84, "price": 1 } }, { "BHKW": { "amount": 307, "price": 58 }, "PV": { "amount": 4, "price": 60 } } ], "2018-08-01T12:00:00+02:00": [{ "BHKW": { "amount": 288, "price": 59 }, "PV": { "amount": 742, "price": 73 } }, { "BHKW": { "amount": 250, "price": 49 }, "PV": { "amount": 507, "price": 98 } }, { "PV": { "amount": 368, "price": 22 }, "BHKW": { "amount": 357, "price": 73 } }, { "FALLBACK": { "amount": 135, "price": 62 }, "BHKW": { "amount": 129, "price": 93 } } ] }

var result =
  _.mapValues(data, (x) =>
    _.reduce(x, (r, c) =>
      _.assignWith(r, c, (o, s) =>
        o && s ? ({ amount: o.amount + s.amount, price: o.price + s.price }) : {...o, ...s})
    )
  )

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>