简体   繁体   English

基于另一个数组过滤具有嵌套 arrays 的对象数组

[英]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:

  1. An object or an array for all filters to be rendered on the screen一个 object 或一个数组,用于在屏幕上呈现的所有过滤器
  2. An object with filters name as a key and the value would be an array of events that has any keyword that matches any of this filter keywords一个 object 过滤器名称作为键,值将是一个事件数组,其中包含与任何此过滤器关键字匹配的任何关键字

check this code example: link检查此代码示例:链接

My Questions:我的问题:

  • Is there an easier/simpler way to solve this problem?有没有更简单/更简单的方法来解决这个问题?
  • I'm passing "filteredTimelineData" object as initial value to.reduce function.我将“filteredTimelineData”object 作为初始值传递给.reduce function。 Is this legitimate?这是合法的吗? I couldn't find any answers online to this question specifically.我在网上找不到这个问题的具体答案。
  • from a time complexity prospective.从时间复杂度的角度来看。 will this code cause any memory issue if the dataset grows?如果数据集增长,此代码会导致任何 memory 问题吗?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM