[英]Filter an array of objects with nested arrays based on another array
I've 2 different APIs.我有 2 个不同的 API。 first one returns an array of event objects (this data set is growing and expected to be large).
第一个返回一个事件对象数组(这个数据集正在增长并且预计会很大)。 each event has a category array that has a list of strings.
每个事件都有一个包含字符串列表的类别数组。 The other API returns an array of filter objects.
另一个 API 返回一个过滤器对象数组。 each filter has a "name" property and an array of keywords.
每个过滤器都有一个“名称”属性和一组关键字。 any keyword included in the categories array in any event should go under this filter name.
在任何情况下,类别数组中包含的任何关键字都应在此过滤器名称下为 go。 The ultimate goal is to have a list of filters on the screen and when a user click on a filter I should render all events under this filter.
最终目标是在屏幕上显示过滤器列表,当用户单击过滤器时,我应该在此过滤器下呈现所有事件。
Event Object Example:事件 Object 示例:
{
"text": {
"headline": "Headline example",
"text": "event description "
},
"media": {
"url": "https://www.google.com/",
"caption": "",
"credit": ""
},
"categories": [
"National",
"Canada",
"British Columbia"
]
}
Filters Object Example:过滤器 Object 示例:
{
"filters": [
{
"keywords": [
"Atlantic",
"New Brunswick",
"Newfoundland and Labrador",
"Prince Edward Island",
"Nova Scotia"
],
"name": "Atlantic"
},
{
"keywords": [
"ontario",
"Quebec"
],
"name": "Central Canada"
},
{
"keywords": [
"Manitoba",
"Saskatchewan",
"Alberta"
],
"name": "Prairie Provinces"
},
{
"keywords": [
"British Columbia"
],
"name": "West Coast"
},
{
"keywords": [
"Nunavut",
"Northwest Territories",
"Yukon Territory"
],
"name": "North"
},
{
"keywords": [
"National"
],
"name": "National"
}
]
}
After a couple of days working on it I came up with this solution.经过几天的努力,我想出了这个解决方案。
function filterTimelineData(filtersObj, timelineData) {
if (!timelineData || !filtersObj) return [];
// create a new object with filters "name" as key;
const filters = Object.keys(filtersObj);
const filteredTimelineData = Object.keys(filtersObj).reduce((o, key) => ({ ...o, [key]: [] }), {});
const filteredData = timelineData.events.reduce((acc, current) => {
let filterMatch = false;
let filterMatchName = '';
for (let i = 0; i < filters.length; i++) {
filterMatch = current.categories.some(item => {
return filtersObj[filters[i]].includes(item.toLocaleLowerCase());
});
if (filterMatch && filterMatchName !== filters[i]) { // to avoid duplicated items with different categories under the same filter
filterMatchName = filters[i];
acc[filters[i]].push(current);
}
}
return acc;
}, filteredTimelineData);
return filteredData;
}
export function timelineFiltersObj(filters) {
const filtersObj = filters.filters.reduce((acc, current) => {
const filterName = current.name.replace(/ /g, '_').toLocaleLowerCase();
if (!acc.hasOwnProperty(filterName)) {
acc[filterName] = [];
}
acc[filterName] = [].concat(current.keywords.map(item => item.toLocaleLowerCase()));
return acc;
}, {});
return filtersObj;
}
Desired output:所需的 output:
check this code example: link检查此代码示例:链接
My Questions:我的问题:
This is a simple way to get the above result.这是获得上述结果的简单方法。 I am using
JavaScript ES5
features in this solution which is supported by almost all the browsers except IE9我在此解决方案中使用
JavaScript ES5
功能,除 IE9 外,几乎所有浏览器都支持
const filters = { "filters": [ { "keywords": [ "Atlantic", "New Brunswick", "Newfoundland and Labrador", "Prince Edward Island", "Nova Scotia" ], "name": "Atlantic" }, { "keywords": [ "ontario", "Quebec" ], "name": "Central Canada" }, { "keywords": [ "Manitoba", "Saskatchewan", "Alberta" ], "name": "Prairie Provinces" }, { "keywords": [ "British Columbia" ], "name": "West Coast" }, { "keywords": [ "Nunavut", "Northwest Territories", "Yukon Territory" ], "name": "North" }, { "keywords": [ "National" ], "name": "National" } ] }; const timelineData = { "events": [ { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "New Brunswick" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "National" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "https://youtu.be/poOO4GN3TN4" }, "categories": [ "Northwest Territories" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "Ontario" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "National" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "https://philanthropy.cdn.redcross.ca/timeline/July2020-3.jpg" }, "categories": [ "British Columbia" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "Alberta" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "Prince Edward Island" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "National" ] }, { "text": { "headline": "headline example", "text": "event-descriprion" }, "media": { "url": "" }, "categories": [ "National" ] } ] }; var categoriesToEventsMap = timelineData.events.reduce((res, event) => { event.categories.forEach(c=> { res = {...res, [c.toLowerCase()]: [...(res[c.toLowerCase()] || []), event] } }); return res; }, {}) var result = filters.filters.reduce((acc, filter) => { let events = [] const filterName = filter.name.replace(' ', '_').toLowerCase(); filter.keywords.forEach((key)=>{ events = [...events, ...(categoriesToEventsMap[key.toLowerCase()] || [])]; }); acc[filterName] = [...(acc[filterName] || []), ...events] return acc; }, {}); console.log(result);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.