【问题标题】:How to get the most recent message of each sender in a collection?如何获取集合中每个发件人的最新消息?
【发布时间】:2020-03-18 10:42:32
【问题描述】:

我有一个这样的对象数组:

const messages = [ 
  {message: "ghhhhhhhh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "12:56"},
  {message: "ggggggghjjgcgh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:45"},
  {message: "good afternoon", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:41"},
  {message: "hfdsghfdfhjo", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:38"},
  {message: "hhhhhhhhhhhhh ", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "11:50"}
];

我想获取每个发件人的最新消息,像这样:

const messages = [
  {message: "ghhhhhhhh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "12:56"},
  {message: "ggggggghjjgcgh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:45"}
];

怎么做?

【问题讨论】:

标签: javascript arrays filter reduce


【解决方案1】:

您可以为此目的使用array.reduce,例如:

const messages = [ {message: "ghhhhhhhh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "12:56"}
, {message: "ggggggghjjgcgh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:45"}
, {message: "good afternoon", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:41"}
, {message: "hfdsghfdfhjo", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:38"}
, {message: "hhhhhhhhhhhhh ", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "11:50"}];


function parseTime(timeStr) {
    const fields = timeStr.split(":").map(parseInt);
    return fields[0] * 60 + fields[1];
}

let result = messages.reduce( (map, item) => { 
   if (!map[item.sender] || parseTime(map[item.sender].time) < parseTime(item.time)) {
       map[item.sender] = item;
   } 
   return map;
}, {});

console.log("Latest messages:", Object.values(result));

【讨论】:

    【解决方案2】:

    你可以这样做:-

    const messages = [ {message: "ghhhhhhhh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "12:56"}
    , {message: "ggggggghjjgcgh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:45"}
    , {message: "good afternoon", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:41"}
    , {message: "hfdsghfdfhjo", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:38"}
    , {message: "hhhhhhhhhhhhh ", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "11:50"}]
    
    const getUniqueMessages = (messages) => {
        const msgMap = {};
        const uniqueMsg = [];
        messages.forEach(item => {
            if(!msgMap[item.sender]) {
                msgMap[item.sender] = true;
                uniqueMsg.push(item)
            }
        });
    
       return uniqueMsg;   
    }
    
    // console.log(getUniqueMessages(messages));
    

    【讨论】:

      【解决方案3】:
      const result = [];
      const map = new Map();
      for (const item of messages) {
          if(!map.has(item.sender)){
              map.set(item.sender, true);
              result.push({
                  message: item.message,
          reciever: item.reciever
                  sender: item.sender,
                  time: item.time
              });
          }
      }
      console.log(result)
      

      【讨论】:

        【解决方案4】:

        一种快速 (O(n)) 且可读性强的方法

        实际上,这是一个非常好的问题。我觉得我可以提供一个比以前的答案更高效的答案(如果您要一遍又一遍地运行此操作,这很重要),同时也非常易于阅读和理解。

        您基本上有一个集合,并希望减少按某个属性对它们进行分组的对象。

        案例1:集合排序

        如果我们可以假设集合首先按最新消息排序(看起来很像),我们可以只保留我们看到的第一个消息:

        const messages = [ 
          {message: "ghhhhhhhh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "12:56"},
          {message: "ggggggghjjgcgh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:45"},
          {message: "good afternoon", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:41"},
          {message: "hfdsghfdfhjo", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:38"},
          {message: "hhhhhhhhhhhhh ", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "11:50"}
        ];
        
        /** @type {Map<String, Object>} */
        const latestMessageBySender = new Map();
        
        // retain the most recent message from every unique sender
        for (const message of messages) {
            if (!latestMessageBySender.has(message.sender)) {
                latestMessageBySender.set(message.sender, message);
            }
        }
        
        // collect and show the resulting messages
        for (const message of latestMessageBySender.values()) {
            console.info(message);
        }

        我们在这里使用Map,这是正确的现代方式(我们的意图比使用旧的、hacky 的{} 更清晰)。

        由于最新消息最先出现,我们只需要检查我们的地图是否已经包含该键。如果是,什么也不做;否则,将当前消息添加到地图中。

        案例2:集合未排序

        另一方面,如果不能保证集合已排序,则不必像其他答案建议的那样解析时间字段,我们可以通过按字典顺序比较字符串来更快地做到这一点:

        if (message1.time > message2.time) {
            // message 1 is more recent than message 2
        }
        

        我们在这里考虑时间戳的格式正确(2 位代表小时,2 位代表分钟,即/\d\d:\d\d/)。换句话说,我们期望04:07 而不是4:7。我们还假设我们只有同一天的消息,因为没有给出日期。

        因此,在这种情况下,最终代码将是:

        const messages = [ 
          {message: "ghhhhhhhh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "12:56"},
          {message: "ggggggghjjgcgh", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:45"},
          {message: "good afternoon", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:41"},
          {message: "hfdsghfdfhjo", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "ZCiuWczin3VuibH59MISuEqR3pc2", time: "12:38"},
          {message: "hhhhhhhhhhhhh ", receiver: "OX0pReHXfXUTq1XnOnTSX7moiGp2", sender: "14", time: "11:50"}
        ];
        
        /** @type {Map<String, Object>} */
        const latestMessageBySender = new Map();
        
        // retain the most recent message from every unique sender
        for (const message of messages) {
            const previousMessage = latestMessageBySender.get(message.sender);
            if (!previousMessage || message.time > previousMessage.time) {
                latestMessageBySender.set(message.sender, message);
            }
        }
        
        // collect and show the resulting messages
        for (const message of latestMessageBySender.values()) {
            console.info(message);
        }

        在向映射添加消息之前,我们首先检查是否已经存在相同键的消息。如果没有,只需添加新的;如果有,按字典顺序比较 time 字段并替换现有字段,以防新字段更新。

        这里需要注意的重要一点是,我们实际上并不希望首先对数组进行排序。那将是O(n log n),但我们可以通过在进行时进行比较来避免O(n)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-12-25
          • 1970-01-01
          • 1970-01-01
          • 2015-05-12
          • 2016-11-02
          • 2019-04-13
          • 2014-01-18
          • 1970-01-01
          相关资源
          最近更新 更多