我怎么能用Lodash实现这个目标?

时间:2017-08-04 15:04:36

标签: javascript arrays object lodash

我想将一组中的2个人之间的所有邮件分组(聊天)。如果我是作者或接收者,那无关紧要。

让我们说一下这个示例代码。

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' } },
]

想象一下,我是用户ID = 1,所以我想得到这个:

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' } },
    ]
  }
];

如何使用Lodash实现这一目标?

3 个答案:

答案 0 :(得分:1)

不确定lodash,但您可以使用普通js - reducemap来获取该结构

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));

答案 1 :(得分:1)

使用Lodash或Underscore.js:

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

你可以将它们组合成一条线,但这对我来说似乎过于密集。

我冒昧地定义了一个更复杂的测试数据集,以确保边缘案例得到更好的覆盖:

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' } }

使用此数据,上面的代码产生formatted

[
  { 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' } }
    ]
  }
]

与所需输出的主要区别在于chatname值。我没看到你是如何命名的,所以我坚持使用Lodash / Underscore的原生groupby键。

答案 2 :(得分:0)

您可以使用_.groupby执行此操作。我首先过滤数组,以便只留下涉及用户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>