本文介绍一种高效、可复用的方法,使用 map + filter 组合对按日期分组的事件数组进行全文搜索,精准匹配标题或摘要中的关键词,并保留原始分组结构,自动剔除无匹配项的空分组。
本文介绍一种高效、可复用的方法,使用 `map` + `filter` 组合对按日期分组的事件数组进行全文搜索,精准匹配标题或摘要中的关键词,并保留原始分组结构,自动剔除无匹配项的空分组。
在实际业务中(如日程管理、活动聚合展示等),数据常以「分组结构」组织:外层数组按时间(如 groupKey)、类别等维度分组,内层 events 数组存放具体条目。此时若需支持关键词搜索(如用户输入“word”查找所有含该词的标题或摘要),不能简单对整个数组调用 filter——那样会破坏分组层级;也不能仅扁平化后搜索再重组——逻辑复杂且性能低。
正确思路是 两阶段处理:
- 逐组映射(map):遍历每个分组,对其 events 子数组执行 filter,保留 title 或 abstract 中包含搜索词的事件(注意大小写不敏感处理);
- 二次过滤(filter):移除经上一步处理后 events 为空数组的分组,确保结果中每个分组至少含一个匹配项。
以下是完整实现代码:
function searchEvents(data, searchTerm) {
if (!Array.isArray(data) || typeof searchTerm !== 'string') {
return [];
}
const normalizedTerm = searchTerm.trim().toLowerCase();
if (normalizedTerm === '') return data; // 空搜索返回原数据(可选策略)
return data
.map(group => {
// 安全校验:确保 group 和 group.events 存在且为数组
const events = Array.isArray(group.events) ? group.events : [];
const filteredEvents = events.filter(event => {
const titleMatch = typeof event.title === 'string' &&
event.title.toLowerCase().includes(normalizedTerm);
const abstractMatch = typeof event.abstract === 'string' &&
event.abstract.toLowerCase().includes(normalizedTerm);
return titleMatch || abstractMatch;
});
return {
...group,
events: filteredEvents
};
})
.filter(group => Array.isArray(group.events) && group.events.length > 0);
}
// 使用示例
const eventData = [
{
"groupKey": "2023-10-12",
"events": [
{ "uid": "4bd2d222", "title": "LEAVE IT TILL LATER", "abstract": "One of the most valuable pieces... made up words..." }
]
},
{
"groupKey": "2023-10-19",
"events": [
{ "uid": "7bbd8c4f", "title": "PLAY ON WORDS", "abstract": "Wordplay is great fun..." },
{ "uid": "LeIaCRXmr", "title": "TRY TO AVOID MADE UP WORDS", "abstract": "try to avoid made up words..." }
]
}
];
console.log(searchEvents(eventData, "word"));
// 输出将只包含 2023-10-12 和 2023-10-19 两个分组,且各自 events 数组仅含匹配项
✅ 关键优势与注意事项:
- 结构守恒:输出格式与输入完全一致(含 groupKey 和 events 字段),前端可直接渲染,无需额外适配;
- 健壮性增强:添加了类型检查(Array.isArray, typeof)和空值防护,避免运行时错误;
- 性能友好:仅遍历数据两次(O(2n) ≈ O(n)),无深层递归或重复展开;
- 扩展灵活:如需支持正则、多字段加权或模糊匹配,只需修改内部 filter 条件即可;
- 大小写处理:统一转为小写比对,提升用户体验(也可根据需求替换为 String.prototype.search() 支持正则)。
? 提示:若需高亮搜索词、支持中文分词或百万级数据,建议结合 Web Worker 或服务端分页搜索。但对于常规前端场景,本方案简洁、可靠、开箱即用。











