【问题标题】:javascript: merge objects with the same master keyjavascript:合并具有相同主密钥的对象
【发布时间】:2020-04-12 15:53:47
【问题描述】:

如何合并具有相同键的对象,例如:

{id: 222, date: 'apr 1', todo: 'nothing' },
{id: 222, date: 'apr 2', todo: '' },
{id: 222, date: 'apr 3', todo: 'swim' },
{id: 222, date: 'apr 4', todo: 'run' },
{id: 222, date: 'apr 1', todo : ''},
{id: 222, date: 'apr 2', todo : 'jump'},
{id: 222, date: 'apr 3', todo : ''},
{id: 222, date: 'apr 4', todo : ''}

结果应该是

{id: 222,
date1: 'apr 1', todo1: 'nothing', 
date2: 'apr 2', todo2: 'jump',
date3: 'apr 3', todo3: 'swim',
date4: 'apr 4', todo4: 'run'
}

我设法以某种方式合并它,但相反,我得到了这个结果......

{id:222, date1: 'apr 1', todo1: 'nothing',
date2: 'apr 2', todo2: '',
date3: 'apr 3', todo3: 'swim',
date4: 'apr 4', todo4: 'run',
date5: 'apr 1', todo5: '',
date6: 'apr 2', todo6: 'jump'
date7: 'apr 3', todo7: '',
date8: 'apr 4', todo8: ''
}

这是我的代码:

var result = Object.values(temp.reduce((r, { id, date, todo }) => {
if (r[id]){
    r[id].payload['date' + r[id].index] = date;
    r[id].payload['todo' + r[id].index] = todo;
    r[id].index++;
} 
else r[id] = { index: 2, payload: { id, date, todo } };
   return r;
}, {}))
.map(({ payload }) => payload);

【问题讨论】:

  • 如果你在同一个组中有更多的待办事项怎么办?
  • 什么意思?
  • @NinaScholz 哦,我明白了,我会编辑我的问题。我提供了错误的结构
  • @aznmik 您想要排序、过滤然后归约。请参阅我的更新答案。

标签: javascript arrays object javascript-objects


【解决方案1】:

尝试使用reduce方法按date属性分组:

let arr = [
    { id: 222, date: 'apr 1', todo: 'nothing' },
    { id: 222, date: 'apr 2', todo: '' },
    { id: 222, date: 'apr 3', todo: 'swim' },
    { id: 222, date: 'apr 4', todo: 'run' },
    { id: 222, date: 'apr 1', todo: '' },
    { id: 222, date: 'apr 2', todo: 'jump' },
    { id: 222, date: 'apr 3', todo: '' },
    { id: 222, date: 'apr 4', todo: '' }
];
const result = arr.reduce((a, { id, date, todo}) => {
    a[date] = a[date] || { id, date, todo};
    if (a[date].todo.length === 0 )
        a[date].todo = todo;
    return a;
}, {})

console.log(Object.values(result));

或者您可以将所有todo 存储在数组中:

const result = arr.reduce((a, { id, date, todo}) => {
    a[date] = a[date] || { id, date, todo:[]};
    a[date].todo.push(todo);
    return a;
}, {})

更新:

更新的输出:

let arr = [
    { id: 222, date: 'apr 1', todo: 'nothing' },
    { id: 222, date: 'apr 2', todo: '' },
    { id: 222, date: 'apr 3', todo: 'swim' },
    { id: 222, date: 'apr 4', todo: 'run' },
    { id: 222, date: 'apr 1', todo: '' },
    { id: 222, date: 'apr 2', todo: 'jump' },
    { id: 222, date: 'apr 3', todo: '' },
    { id: 222, date: 'apr 4', todo: '' }
];

const result = arr.reduce((a, { id, date, todo}) => {
    a[id] = a[id] || { id };
    let key = date.split(' ').pop();
    a[id]['date' + key] = date;
    a[id]['todo' + key] = (todo.length > 0) ? todo : a[id]['todo' + key];
    return a;
}, {})
console.log(Object.values(result));

更新 1:

let arr = [
    { id: 222, date: 'apr 1', todo: 'nothing' },
    { id: 222, date: 'apr 2', todo: '' },
    { id: 222, date: 'apr 3', todo: 'swim' },
    { id: 222, date: 'apr 4', todo: 'run' },
    { id: 222, date: 'apr 1', todo: '' },
    { id: 222, date: 'apr 2', todo: 'jump' },
    { id: 222, date: 'apr 3', todo: '' },
    { id: 222, date: 'apr 4', todo: '' }
];

const groupedById = Object.values(arr.reduce((a, { id, date, todo}) => {
    a[id] = a[id] || { id };
    a[id][date] = a[id][date] || {date};
    if (todo.length > 0 && !a[id][date]['todo'])
        a[id][date]['todo'] = todo;
    return a;
}, {}));

const result = groupedById.reduce((a, {id, ...rest})=> {
    let count = 0;
    for (const key in rest) {
        count++;
        a['date' + count] =rest[key].date;
        a['todo' + count] =rest[key].todo;
    }
    a[id] = id;
    return a;
}, {})

console.log(result);

【讨论】:

  • @StepUp 我编辑了这个问题。介意看看吗? :)
  • 是的,看来是这样,我还没有检查原始要求:/
  • @aznmik 我建议使用数组或对象来存储合并数据,而不是 date1,date2... 之类的属性
  • @CodeManiac 是的,这是理想的方式,但出于某种原因,我不得不这样做 :)
  • @StepUp 你已经得到了我的支持,但date1,date2id 的元素数量决定,而不是由date.split(' ').pop() 决定
【解决方案2】:

您可以使用一个对象进行分组并存储每个新日期/待办事项对的后缀编号。

结果从对象中获取值/有效负载。

var data = [{id: 222, date: 'apr 1', todo: 'nothing' }, { id: 222, date: 'apr 2', todo: '' }, { id: 222, date: 'apr 3', todo: 'swim' }, { id: 222, date: 'apr 4', todo: 'run' }, { id: 222, date: 'apr 1', todo : '' }, { id: 222, date: 'apr 2', todo : 'jump' }, { id: 222, date: 'apr 3', todo : '' }, { id: 222, date: 'apr 4', todo : '' }],
    result = Object
        .values(data.reduce((r, { id, date, todo }) => {
            if (!r[id]) r[id] = { index: 0, key: {}, payload: { id } };
            if (!r[id].key[date]) {                    
                r[id].index++;
                r[id].key[date] = `todo${r[id].index}`;
                r[id].payload[`date${r[id].index}`] = date;
            }
            if (todo) r[id].payload[r[id].key[date]] = todo;
            return r;
        }, {}))
        .map(({ payload }) => payload);

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

【讨论】:

  • 如果我有另一个对象,比如说,{id: 222, date: 'apr 5', todo: ' ' }... 我仍然希望在结果中附加它?跨度>
  • 实际上它附加了一个新的日期和空字符串的待办事项。如果不需要,我可以删除添加空的初始(相同日期)字符串。
  • 这并没有真正回答我的问题,但很接近。我会尝试稍微调整一下。谢谢你:)
【解决方案3】:

这可以通过sort()filter()reduce()来实现:

let arr=[{id:222,date:"apr 1",todo:"nothing"},{id:222,date:"apr 2",todo:""},{id:222,date:"apr 3",todo:"swim"},{id:222,date:"apr 4",todo:"run"},{id:222,date:"apr 1",todo:""},{id:222,date:"apr 2",todo:"jump"},{id:222,date:"apr 3",todo:""},{id:222,date:"apr 4",todo:""}];

let res = arr.sort((a, b) => {
  return (a.date > b.date) ? 1 : -1
}).filter(el => {
  return el.todo
}).reduce((acc,el,idx) => {
    !("id" in acc) && (acc.id = 222)
    return el.id === 222 ? Object.assign(acc, {["date" + (idx+1)] : el.date, ["todo" + (idx+1)] : el.todo}) : acc
},{})

console.log(res)

【讨论】:

    猜你喜欢
    • 2019-08-02
    • 2017-06-24
    • 1970-01-01
    • 2022-11-01
    • 2020-06-20
    • 1970-01-01
    • 2016-08-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多