在lodash中使用键值合并一个对象数组?

时间:2020-11-30 15:57:56

I'm using node.js and lodash.

我正在使用node.js和lodash。

I have data like this:

我有这样的数据:

[ 
  { 
    to: [ 'foo@bar.com', 'foo1@bar.com' ],
    submittedSubs: [ [Object] ] 
  },
  { 
    to: [ 'foo@bar.com', 'foo2@bar.com' ],
    submittedSubs: [ [Object], [Object], [Object] ] 
  } 
]

I'd like to turn it into data like this where it's "sorted" by to

我想把它变成这样的数据,它被“排序”到

[ 
  { 
    to: 'foo@bar.com', 
    submittedSubs: [ [Object],[Object], [Object], [Object] ] 
  },
  { 
    to: 'foo1@bar.com', 
    submittedSubs: [ [Object] ] 
  },
  { 
    to: 'foo2@bar.com',
    submittedSubs: [ [Object], [Object], [Object] ] 
  }
]

How can I do this?

我怎样才能做到这一点?

I've tried this:

我试过这个:

spam[0].to.push('foo@bar.com');  
spam[0].to.push('foo1@bar.com'); 
spam[1].to.push('foo@bar.com');  
spam[1].to.push('foo2@bar.com'); 

console.log('data is',spam);

var byUser=[];
_.each(spam, function(data){
    _.each(data.to,function(addr){
        byUser.push({to:addr,submittedSubs:data.submittedSubs});
    });
});
console.log('attempt',_.merge(byUser));

But that gives me this:

但这给了我这个:

[ { to: 'foo@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo1@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo@bar.com', submittedSubs: [ [Object], [Object], [Object] ] },
{ to: 'foo2@bar.com', submittedSubs: [ [Object], [Object], [Object] ] } ]

2 个解决方案

#1


1  

This'll work for you:

这对你有用:

var unique = {};
byUser.forEach(function(user) {
    unique[user.to] = unique[user.to] || [];
    unique[user.to] = unique[user.to].concat(user.submittedSubs);
});
unique = Object.keys(unique).map(function (key, i) {
    return {to: key, submittedSubs: unique[key]};
});

/*
[ { to: 'foo@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo1@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo2@bar.com', submittedSubs: [ [Object], [Object], [Object], [Object] ] } ]
*/

I stand by that this should be achievable using the callback feature of _.uniq but I couldn't get it to work the way you needed it to.

我支持这应该可以使用_.uniq的回调功能实现,但我无法让它以你需要的方式工作。

You should be able to use _.uniq from on your final array:

你应该可以在最后一个数组上使用lodash的_.uniq:

_.uniq(byUser, "to");

/*
[ { to: 'foo@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo1@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo2@bar.com', submittedSubs: [ [Object], [Object], [Object] ] } ]
*/

#2


1  

I imagine there's some nice lodash facilities to shorten this up a bit, but here's a vanilla-js solution:

我想有一些不错的lodash设施可以缩短它,但这里有一个vanilla-js解决方案:

var data = [ 
  { 
    to: [ 'foo@bar.com', 'foo1@bar.com' ],
    submittedSubs: [{ id: 'sub1' }] 
  },
  { 
    to: [ 'foo@bar.com', 'foo2@bar.com' ],
      submittedSubs: [{ id: 'sub2' }, { id: 'sub3' }, { id: 'sub4' }]
  } 
];

var emailSubsMap = data.reduce(function(result, record) {
    record.to.forEach(function(email) {
        result[email] = (result[email] || [])
            .concat(record.submittedSubs);
    });
    return result;
}, {});

var formatted = Object.keys(emailSubsMap).map(function(email) {
    return { to: email, submittedSubs: emailSubsMap[email] };
}).sort(function(a, b) {
    return a.to <= b.to ? -1 : 1;
});

console.log(JSON.stringify(formatted));

(Formatted) console output:

(格式化)控制台输出:

[
    {
        "to": "foo1@bar.com",
        "submittedSubs": [
            { "id": "sub1" }
        ]
    },
    {
        "to": "foo2@bar.com",
        "submittedSubs": [
            { "id": "sub2" },
            { "id": "sub3" },
            { "id": "sub4" }
        ]
    },
    {
        "to": "foo@bar.com",
        "submittedSubs": [
            { "id": "sub1" },
            { "id": "sub2" },
            { "id": "sub3" },
            { "id": "sub4" }
        ]
    }
]

Note that I mocked up what the submittedSubs objects might look like, simply for testing purposes.

请注意,我模拟了submittedSubs对象的外观,仅用于测试目的。

JSFiddle Example

A couple notes about the sorting:

关于排序的几个注意事项:

  • My first version wasn't sorting correctly... it's been updated. :)
  • 我的第一个版本没有正确排序......它已经更新。 :)

  • The sort method you're requesting doesn't follow JavaScript's "native" string sort order. E.g., ['foo@bar.com', 'foo2@bar.com', 'foo1@bar.com'].sort() --> ['foo1@bar.com','foo2@bar.com','foo@bar.com'], so if you really want foo@bar.com to come before foo1@bar.com, you'll need to define your sort criteria in a little more detail.
  • 您请求的排序方法不遵循JavaScript的“本机”字符串排序顺序。例如,['foo@bar.com','foo2 @ bar.com','foo1 @ bar.com'] .sort() - > ['foo1@bar.com','foo2 @ bar.com' ,'foo @ bar.com'],所以如果你真的希望foo@bar.com在foo1@bar.com之前来,你需要更详细地定义你的排序标准。

#1


1  

This'll work for you:

这对你有用:

var unique = {};
byUser.forEach(function(user) {
    unique[user.to] = unique[user.to] || [];
    unique[user.to] = unique[user.to].concat(user.submittedSubs);
});
unique = Object.keys(unique).map(function (key, i) {
    return {to: key, submittedSubs: unique[key]};
});

/*
[ { to: 'foo@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo1@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo2@bar.com', submittedSubs: [ [Object], [Object], [Object], [Object] ] } ]
*/

I stand by that this should be achievable using the callback feature of _.uniq but I couldn't get it to work the way you needed it to.

我支持这应该可以使用_.uniq的回调功能实现,但我无法让它以你需要的方式工作。

You should be able to use _.uniq from on your final array:

你应该可以在最后一个数组上使用lodash的_.uniq:

_.uniq(byUser, "to");

/*
[ { to: 'foo@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo1@bar.com', submittedSubs: [ [Object] ] },
{ to: 'foo2@bar.com', submittedSubs: [ [Object], [Object], [Object] ] } ]
*/

#2


1  

I imagine there's some nice lodash facilities to shorten this up a bit, but here's a vanilla-js solution:

我想有一些不错的lodash设施可以缩短它,但这里有一个vanilla-js解决方案:

var data = [ 
  { 
    to: [ 'foo@bar.com', 'foo1@bar.com' ],
    submittedSubs: [{ id: 'sub1' }] 
  },
  { 
    to: [ 'foo@bar.com', 'foo2@bar.com' ],
      submittedSubs: [{ id: 'sub2' }, { id: 'sub3' }, { id: 'sub4' }]
  } 
];

var emailSubsMap = data.reduce(function(result, record) {
    record.to.forEach(function(email) {
        result[email] = (result[email] || [])
            .concat(record.submittedSubs);
    });
    return result;
}, {});

var formatted = Object.keys(emailSubsMap).map(function(email) {
    return { to: email, submittedSubs: emailSubsMap[email] };
}).sort(function(a, b) {
    return a.to <= b.to ? -1 : 1;
});

console.log(JSON.stringify(formatted));

(Formatted) console output:

(格式化)控制台输出:

[
    {
        "to": "foo1@bar.com",
        "submittedSubs": [
            { "id": "sub1" }
        ]
    },
    {
        "to": "foo2@bar.com",
        "submittedSubs": [
            { "id": "sub2" },
            { "id": "sub3" },
            { "id": "sub4" }
        ]
    },
    {
        "to": "foo@bar.com",
        "submittedSubs": [
            { "id": "sub1" },
            { "id": "sub2" },
            { "id": "sub3" },
            { "id": "sub4" }
        ]
    }
]

Note that I mocked up what the submittedSubs objects might look like, simply for testing purposes.

请注意,我模拟了submittedSubs对象的外观,仅用于测试目的。

JSFiddle Example

A couple notes about the sorting:

关于排序的几个注意事项:

  • My first version wasn't sorting correctly... it's been updated. :)
  • 我的第一个版本没有正确排序......它已经更新。 :)

  • The sort method you're requesting doesn't follow JavaScript's "native" string sort order. E.g., ['foo@bar.com', 'foo2@bar.com', 'foo1@bar.com'].sort() --> ['foo1@bar.com','foo2@bar.com','foo@bar.com'], so if you really want foo@bar.com to come before foo1@bar.com, you'll need to define your sort criteria in a little more detail.
  • 您请求的排序方法不遵循JavaScript的“本机”字符串排序顺序。例如,['foo@bar.com','foo2 @ bar.com','foo1 @ bar.com'] .sort() - > ['foo1@bar.com','foo2 @ bar.com' ,'foo @ bar.com'],所以如果你真的希望foo@bar.com在foo1@bar.com之前来,你需要更详细地定义你的排序标准。