简体   繁体   中英

How can I achieve this with Lodash?

I would like to group all messages between 2 people in a group (chat). Doesn`t matter if I am the author or receiver.

Let's say this example code.

const messages = [
  { id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
  { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
  { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
]

Imagine, I am user ID = 1, so I would like to get this:

const chats = [
  {
    chatName: 'Name of user ID 2', messages: [
      { id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
      { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
    ]
  },
  {
    chatName: 'Name of user ID 3', messages: [
      { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
    ]
  }
];

How can I achieve this with Lodash?

Not sure about lodash, but you can use plain js - reduce and map to get that structure

 const messages = [{ id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } }, { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } }, { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } }, ]; function groupByPair(arr) { return [ ...arr.reduce((a, b) => { let { author, receiver } = b; let s = [author.id, receiver.id].sort().join('-'); a.set(s, a.has(s) ? a.get(s).concat(b) : [b]); return a; }, new Map) ].map(e => ({ chatName: 'Name of user ID ' + e[0].substring(e[0].indexOf('-') + 1), messages: e[1] })); } console.log(groupByPair(messages)); 

Using either Lodash or Underscore.js:

var grouped = _.groupBy(messages, m => _.sortBy([m.author.id, m.receiver.id]));
var formatted = _.map(grouped, (v, name) => ({ chatname: name, messages: v }));

You could combine those into a single line, but that seems overly dense to my eyes.

I took the liberty of defining a more complex test dataset, to make sure the edge cases were better covered:

var messages = [
  { id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
  { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
  { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
  { id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } },
  { id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } },
  { id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }

]

With this data, the code above yields a formatted of:

[
  { chatname: '1,2',
    messages: [
      { id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } },
      { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } },
      { id: '103', text: 'zzz', author: { id: '2' }, receiver: { id: '1' } }
    ]
  },
  { chatname: '1,3', messages: [
      { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } },
      { id: '105', text: 'xxx', author: { id: '3' }, receiver: { id: '1' } }
    ]
  },
  { chatname: '3,4', messages: [
      { id: '104', text: 'yyy', author: { id: '3' }, receiver: { id: '4' } }
    ]
  }
]

The major difference with your desired output relates to the chatname values. I did not see how you were naming those, so I stuck with Lodash/Underscore's native groupby keys.

You can do this with _.groupby . I filter the array first so that you're only left with messages that involve user 1.

 const messages = [ { id: '100', text: 'aaa', author: { id: '1' }, receiver: { id: '2' } }, { id: '101', text: 'bbb', author: { id: '2' }, receiver: { id: '1' } }, { id: '102', text: 'ccc', author: { id: '3' }, receiver: { id: '1' } }, ]; const filtered = messages.filter((msg) => { return msg.author.id === '1' || msg.receiver.id === '1' }); const groups = _.groupBy(filtered, (msg) => { return msg.author.id === '1' ? msg.receiver.id : msg.author.id }); console.log(groups); 
 <script src="https://unpkg.com/lodash@4.17.4"></script> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM