【问题标题】:Filter an array of objects based on another array and a condition根据另一个数组和条件过滤一组对象
【发布时间】:2022-01-19 00:19:51
【问题描述】:

我正在努力根据特定条件从一组对象中检索一个子集。我有以下格式的对象数组:

const messages = [
    {
        summary: '[x1fg66pwq-qft] Second reminder to submit supporting documents',
        date: '1624652200',
        type: 1
    },
    {
        summary: '[x1fg66pwq-fgh] Final reminder to submit supporting documents',
        date: '1629058600',
        type: 4
    },
    {
        summary: '[zy9l89ptb-yuw] Please submit your proof of address',
        date: '1631708200',
        type: 2
    },
    {
        summary: '[ggk9nygh8-pmn] Your application has been successful.',
        date: '1634300200',
        type: 1
    },
]

还有另一个数组,它根据摘要方括号中的消息 ID 提供要检索的消息:

const messageIds = ['x1fg66pwq', 'zy9l89ptb'];

结果应该是根据messageIds 数组中的内容检索最新消息。日期字段以纪元为单位。

const result = [
    {
        summary: '[x1fg66pwq] Final reminder to submit supporting documents',
        date: '1629058600',
        type: 4
    },
    {
        summary: '[zy9l89ptb] Please submit your proof of address',
        date: '1631708200',
        type: 2
    },
]

为了实现上述目的,我尝试组合一个过滤器并找到对我不起作用的:

const result = messages.filter((message) =>
        messageIds.find(id => message.summary.includes(testEvent))
    );

我希望上面返回数组中指定摘要的第一个结果。但是,这总是为我返回完整的数组而不过滤。有人可以帮我实现这一目标吗?

【问题讨论】:

  • 我认为您的方法没有问题。它返回过滤后的消息数组,其中包含在您的messageIds 中指定的相同摘要。我尝试执行它,并得到一个包含 3 个项目而不是 4 个项目的新数组。现在您只需要获取最新消息。我错了吗?
  • 是的,我只需要获取最新的,我认为这是我的方法不起作用的地方
  • @Julien 绝对。代码按预期工作。他实际上有两个具有相同 ID 的摘要。他想要最新的。
  • 你的做法没有错。你只需要一步一步地做事。在这里,您已经过滤了您的数组。现在您可以按 ID 对其进行分组,然后按日期对每个组进行排序,然后从每个组中取出第一项。这样您就会收到最新消息。
  • 抱歉,我在消息对象中遗漏了一些内容。方括号中的字符串是 id 后跟一个具有潜在含义的三个字母的单词。 messagesId 数组只包含 id 而不是三个字母的单词。帖子已更新

标签: javascript arrays algorithm ecmascript-6 filtering


【解决方案1】:

如果我正确理解您的问题,我认为您只需要在最后添加sort

.sort((b,a) => +a.date - +b.date)

const messages = [{
    summary: '[x1fg66pwq-qft] Second reminder to submit supporting documents',
    date: '1624652200',
    type: 1
  },
  {
    summary: '[x1fg66pwq-fgh] Final reminder to submit supporting documents',
    date: '1629058600',
    type: 4
  },
  {
    summary: '[zy9l89ptb-yuw] Please submit your proof of address',
    date: '1631708200',
    type: 2
  },
  {
    summary: '[ggk9nygh8-pmn] Your application has been successful.',
    date: '1634300200',
    type: 1
  },
]

const messageIds = ['x1fg66pwq', 'zy9l89ptb'];

const result = messages.filter((message) =>
  messageIds.some(id => message.summary.includes(id))
).sort((b, a) => +a.date - +b.date);

console.log(result)

【讨论】:

  • 为什么find ...?
  • @NinaScholz - 谢谢。我切换到findIndex >-1 以获得过滤器的布尔值。
  • 为什么不改用some?它返回一个布尔值。
  • @NinaScholz - 谢谢
【解决方案2】:

当您寻找最新的时,您可以首先创建一个映射或普通对象,以目标消息 ID 为键,然后将其@987654321 具有最大价值的每个消息分配给@属性:

const messages = [{summary: '[x1fg66pwq-qft] Second reminder to submit supporting documents',date: '1624652200',type: 1},{ summary: '[x1fg66pwq-fgh] Final reminder to submit supporting documents',date: '1629058600', type: 4},{ summary: '[zy9l89ptb-yuw] Please submit your proof of address',date: '1631708200',type: 2},{  summary: '[ggk9nygh8-pmn] Your application has been successful.', date: '1634300200',type: 1},];

const messageIds = ['x1fg66pwq', 'zy9l89ptb'];

// Create object keyed by the message ids:
let obj = Object.fromEntries(messageIds.map(id => [id, null]));
// Link the message to each id with minimal date
for (let msg of messages) {
    let id = msg.summary.match(/^\[(.*?)-/)?.[1];
    if (obj[id] === null || +msg.date > +obj[id]?.date) obj[id] = msg;
}

let result = Object.values(obj);

console.log(result);

【讨论】:

    【解决方案3】:

    这很容易。只需将它们串在一起即可:

    const matches = (messages, ids) => ids .flatMap (
      id => messages .filter (({summary}) => summary .startsWith ('[' + id))
                     .sort (({date: a}, {date: b}) => b - a)
                     .slice (0, 1)
    )
    
    const messages = [{summary: '[x1fg66pwq-qft] Second reminder to submit supporting documents', date: '1624652200', type: 1}, {summary: '[x1fg66pwq-fgh] Final reminder to submit supporting documents', date: '1629058600', type: 4}, {summary: '[zy9l89ptb-yuw] Please submit your proof of address', date: '1631708200', type: 2}, {summary: '[ggk9nygh8-pmn] Your application has been successful.', date: '1634300200', type: 1}]
    
    const messageIds = ['x1fg66pwq', 'zy9l89ptb']
    
    console .log (matches (messages, messageIds))

    此版本将简单地忽略不匹配的 id。这可能是也可能不是你想要的。如果您必须为每个 id 搜索大量数据,它也会做一些愚蠢的事情:它通过对它们进行排序并选择第一个来找到最大值。对于小数据,这很好。对于较大的数据(可能首先出现问题的可能是数十万或数百万),这是O (n log (n)),它比以下技术慢,即O (n)

    const maxBy = (fn) => (xs) => xs .reduce (
      ({curr, max}, x) => fn(x) > max ? {curr: x, max: fn (x)} : {curr, max}, 
      {curr: null, max: -Infinity}
    ) .curr
    
    const matches = (messages, ids) => ids .flatMap (
      id => maxBy (({date}) => Number(date)) 
                  (messages .filter (({summary}) => summary .startsWith ('[' + id)))
    )
    
    const messages = [{summary: '[x1fg66pwq-qft] Second reminder to submit supporting documents', date: '1624652200', type: 1}, {summary: '[x1fg66pwq-fgh] Final reminder to submit supporting documents', date: '1629058600', type: 4}, {summary: '[zy9l89ptb-yuw] Please submit your proof of address', date: '1631708200', type: 2}, {summary: '[ggk9nygh8-pmn] Your application has been successful.', date: '1634300200', type: 1}]
    
    const messageIds = ['x1fg66pwq', 'zy9l89ptb']
    
    console .log (matches (messages, messageIds))

    这使用了一个maxBy 函数,它遍历列表以根据提供的函数找到最大值,返回一个空数组的null

    如果找不到 id,此版本将在输出中包含 null。这可能是首选行为,但如果不是,您可以包装它以过滤非空值的输出。

    显然,在这两种解决方案中,您都可以将summary .startsWith ('[' + id) 替换为summary .includes (id),这样更灵活,但可能不太精确。

    【讨论】:

      猜你喜欢
      • 2019-09-15
      • 2019-04-05
      • 2019-09-30
      • 2021-10-24
      • 2022-11-30
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多