在 JavaScript 中聚合对象数组

Posted

技术标签:

【中文标题】在 JavaScript 中聚合对象数组【英文标题】:Aggregate an array of objects in JavaScript 【发布时间】:2020-02-14 13:30:18 【问题描述】:

我有一个包含布尔字段 X 的对象数组。[..., x: true, y: 3, ...]

如果x所有值对应true(或@987654326 @),否则 undefined... 和 y 的总和...

是否可以使用reduce Array 函数、groupby by underscorejs 或其他用于此目的的函数?

例如:

[
 a:'titi', x: true,  y: 3, 
 a:'toto', x: false, y: 6
]

结果

       x: undefined, y: 9

【问题讨论】:

@georg,这不仅仅是一个单一的操作,而是一个复杂的对象...... 好的,我明白了,重新打开 【参考方案1】:

reduce 非常简单:

.reduce((a, b) => (
   x: a.x == b.x ? a.x : undefined,
   y: a.y + b.y
))

活生生的例子:

var input = [
       a:'titi', x: true,  y: 3, 
       a:'toto', x: false, y: 6
    ];
    
console.log(input.reduce((a, b) => (
   x: a.x == b.x ? a.x : undefined,
   y: a.y + b.y
)));

【讨论】:

这很酷,当然它会创建一堆不必要的对象。不过,99.9% 的时间都没有关系。【参考方案2】:

我使用reduce 提出了这个解决方案。似乎有点hacky,但它应该可以完成这项工作。在缩减数组时,它会确定每个 x 值是否相等,然后相应地设置缩减对象的 x 值。

let reduced = arr.reduce((acc, curr) => 
    acc.x &= acc.x_init === curr.x;
    acc.y += curr.y;
  , x_init: arr[0].x, x: true, y: 0);
reduced.x = reduced.x ? reduced.x_init : undefined;
delete reduced.x_init;

【讨论】:

【参考方案3】:

虽然您可以将其塞入reduce 调用中(因为任何数组操作都可以塞入reduce),但这样做没有任何好处。只需使用循环:

const result = x: null, y: 0;
for (const entry of array) 
    if (result.x === null) 
        result.x = entry.x;
     else if (result.x !== entry.x) 
        result.x = undefined;
    
    result.y += entry.y;

现场示例:

function check(array) 
    const result = x: null, y: 0;
    for (const entry of array) 
        if (result.x === null) 
            result.x = entry.x;
         else if (result.x !== entry.x) 
            result.x = undefined;
        
        result.y += entry.y;
    
    console.log(result);

check([
 a:'titi', x: true,  y: 3, 
 a:'toto', x: false, y: 6
]);
console.log("---");
check([
 a:'titi', x: true,  y: 3, 
 a:'toto', x: true, y: 6
]);
console.log("---");
check([
 a:'titi', x: false,  y: 3, 
 a:'toto', x: false, y: 6
]);
console.log("---");

但是,如果您愿意,您可以通过始终返回相同的对象将其硬塞到 reduce

const result = array.reduce((obj, entry) => 
    if (obj.x === null) 
        obj.x = entry.x;
     else if (obj.x !== entry.x) 
        obj.x = undefined;
    
    obj.y += entry.y;
    return obj;
, x: null, y: 0);

现场示例:

function check(array) 
    const result = array.reduce((obj, entry) => 
        if (obj.x === null) 
            obj.x = entry.x;
         else if (obj.x !== entry.x) 
            obj.x = undefined;
        
        obj.y += entry.y;
        return obj;
    , x: null, y: 0);
    console.log(result);

check([
 a:'titi', x: true,  y: 3, 
 a:'toto', x: false, y: 6
]);
console.log("---");
check([
 a:'titi', x: true,  y: 3, 
 a:'toto', x: true, y: 6
]);
console.log("---");
check([
 a:'titi', x: false,  y: 3, 
 a:'toto', x: false, y: 6
]);
console.log("---");

但是,如果您想要reduce 解决方案并且不介意创建一堆临时丢弃对象,请查看Adassko's answer。简单直接,而且在 99.9% 的情况下,您都不关心临时对象的创建。

【讨论】:

【参考方案4】:

感谢@Adassko,我的变种有点长:

[
  a:'titi', x: false,  y: 3, 
  a:'toto', x: false, y: 6
]
.reduce((a, b, i) => (
  x : a.x === b.x || i == 0 ? b.x : undefined,
  y : a.y + b.y
))

【讨论】:

以上是关于在 JavaScript 中聚合对象数组的主要内容,如果未能解决你的问题,请参考以下文章

如何仅在猫鼬中使用聚合填充嵌套在对象数组中的字段?

使用 pymongo 从多个更高级别的数组对象聚合嵌套数组对象

如何将对象响应对象的猫鼬聚合数组转换为json对象响应

Linq 接口列表,接口有成员字符串数组,我想要 linq 语句聚合对象数组中的所有字符串

数组中字段的最小值和数组mongodb聚合查询中的第一个对象

聚合查找作为数组一部分的对象