【问题标题】:Group duplicate of same value within object of an array对数组对象中相同值的重复分组
【发布时间】:2017-11-12 18:27:10
【问题描述】:
[{
    "_id": {
        "year": 2017,
        "month": 4
    },
    "Confirm": 0
}, {
    "_id": {
        "year": 2017,
        "month": 4
    },
    "Expired": 25
}, {
    "_id": {
        "year": 2017,
        "month": 4
    },
    "Pending": 390
}, {
    "_id": {
        "year": 2017,
        "month": 5
    },
    "Pending": 1400
}]

上面的数组包含相同的月份和年份。从 MongoDB 聚合生成。我想将它们合并到一个对象中并保留它们拥有的任何键和值。

预期输出:

[{
    month: 4,
    year: 2017,
    Expired: 25,
    Pending: 390
}, {
    month: 5,
    year: 2017,
    Pending: 1400
}]

我更喜欢最快的执行实现。欢迎使用 Underscorejs 或 native。谢谢

【问题讨论】:

  • 你想如何合并它们?提供您的expected output
  • 有些键匹配但不是整个对象...它们是否也合并为一个对象?
  • 是的@zer00ne。我是否必须引入另一个变量
  • 所以"Confirm": 0 也应该在结果的第一个对象中?
  • 没关系。键的顺序不是我关心的问题

标签: javascript


【解决方案1】:

这在 O(N*logN) 中运行用于排序和 O(N) 用于合并 json。 希望这对你有用!

var obj = [{
    _id: {
        year: 2017,
        month: 5,
    },
    Pending: 1400,
}, {
    _id: {
        year: 2017,
        month: 4,
    },
    Expired: 25,
}, {
    _id: {
        year: 2017,
        month: 4,
    },
    Pending: 390,
}, {
    _id: {
        year: 2017,
        month: 4,
    },
    Confirm: 0,
}];

function compare(a, b) {
    return a._id.year !== b._id.year
        ? a._id.year - b._id.year
        : a._id.month - b._id.month;
}

var sorted = obj.sort(compare);

function join(a, b) {
    return {
        _id: a._id,
        Pending: (a.Pending? a.Pending : 0) + (b.Pending? b.Pending : 0),
        Confirm: (a.Confirm? a.Confirm : 0) + (b.Confirm? b.Confirm : 0),
        Expired: (a.Expired? a.Expired : 0) + (b.Expired? b.Expired : 0),
    };
}

var compressed = sorted.filter(function (value, index) {
    if (!sorted[index + 1]) {
        return true;
    }
    if (compare(value, sorted[index + 1]) === 0) {
        sorted[index + 1] = join(value, sorted[index + 1]);
        return false;
    }
    return true;
});

console.log(compressed);

// if you want month and year formatted:

console.log(compressed.map(function (o) {
    const result = {
        month: o._id.month,
        year: o._id.year,
    };
    if (o.Pending !== undefined) result.Pending = o.Pending;
    if (o.Confirm !== undefined) result.Confirm = o.Confirm;
    if (o.Expired !== undefined) result.Expired = o.Expired;
    return result;
}));

【讨论】:

    【解决方案2】:

    这需要一点时间来区分,但它是线性的:

    const ary = [{
        "_id": {
            "year": 2017,
            "month": 4
        },
        "Confirm": 0
    }, {
        "_id": {
            "year": 2017,
            "month": 4
        },
        "Expired": 25
    }, {
        "_id": {
            "year": 2017,
            "month": 4
        },
        "Pending": 390
    }, {
        "_id": {
            "year": 2017,
            "month": 5
        },
        "Pending": 1400
    }];
    
    const result = Object.values(ary.reduce((acc, cur) => {
        const { month, year } = cur._id;
        const key = `${month}-${year}`;
        const obj = Object.assign({}, cur);
        delete obj._id;
        acc[key] = Object.assign(acc[key] || { month, year }, obj);
        return acc;
    }, {}));
    
    console.log(result);
    

    【讨论】:

    • @DanielPérez,使用键时不需要排序。
    • 我想mongodb查询没有必要,在这种情况下应该更新问题,添加mongodb标签等
    • @DanielPérez,它与 mongodb 无关。这就是 JS 对象的工作原理。
    • 运行它并询问你不明白的地方:)
    • 我运行了它,它抛出了一个错误,const result = Object.values(ary.reduce((acc, cur) => { ^ TypeError: Object.values is not a function
    【解决方案3】:

    您可以使用Map 进行分组,然后使用Array.from 提取最终对象:

    function merge(data) {
        return Array.from(data.reduce( (acc, o) => {
            const k = o._id.year * 100 + o._id.month;
            const v = acc.get(k) || Object.assign({}, o._id);
            for (let prop in o) {
                if (prop !== '_id') v[prop] = o[prop];
            }            
            return acc.set(k, v);
        }, new Map), ([k, v]) => v);
    }
    // Sample data
    const data = [{
        "_id": {
            "year": 2017,
            "month": 4
        },
        "Confirm": 0
    }, {
        "_id": {
            "year": 2017,
            "month": 4
        },
        "Expired": 25
    }, {
        "_id": {
            "year": 2017,
            "month": 4
        },
        "Pending": 390
    }, {
        "_id": {
            "year": 2017,
            "month": 5
        },
        "Pending": 1400
    }];
    
    const result = merge(data);
    
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-25
      • 1970-01-01
      • 2021-10-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多