根据另一个数组和条件过滤一组对象
Posted
技术标签:
【中文标题】根据另一个数组和条件过滤一组对象【英文标题】: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 而不是三个字母的单词。帖子已更新
【参考方案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)
,这样更灵活,但可能不太精确。
【讨论】:
以上是关于根据另一个数组和条件过滤一组对象的主要内容,如果未能解决你的问题,请参考以下文章
BigQuery LEFT JOIN 一个表并根据条件过滤其数组元素
如何过滤复杂对象的列表,以便如果两个具有字段值,我会根据条件删除一个