如何有效过滤嵌套数组和对象结构的最底部项目,同时保留这些项目的路径信息?

问题描述

我有如下数据数组。

一个大陆数组,每个大陆都有一个地区数组,每个大陆都有一个国家数组。例如

continents:[
  {
     Name: 'Europe',Regions: [
       {
         Name: Western Europe,Countries: [
           {
             Name: 'United Kingdom'
           },{
             Name: 'Republic of Ireland'
           }
         ]
       }
     ]
  }
]

我有一个搜索字段,用户可以在其中搜索一个国家/地区。 我需要做的是能够过滤结果以仅显示国家/地区的搜索,但同时显示地区和大洲。

例如如果用户搜索“United”,它将显示

Europe
  -> Western Europe
     -> **United** Kingdom

Americas
  -> north America
     -> **United** States of America

我撞墙了。任何建议将不胜感激。

谢谢

解决方法

查看给定的数据结构和 OP 的任务,一个人必须做的第一件事是(恰好一次)重新组装或将给定的结构reduce 变成一个国家项目的平面列表,其中每个项目除了它的country 字段还包含该国家/地区的 regioncontinent 属性......类似这样......

...,{
  country: "Republic of Ireland",region: "Western Europe",continent: "Europe"
},{
  country: "Indonesia",region: "Southeast Asia",continent: "Asia"
},...

然后可以以非常简单的方式实现仍然开放的搜索/查询任务,filter寻找任何项目的小写名称includes同样lowercase名称查询...

function queryCountryListByName(nameQuery) {
  return listOfCountryItems.filter(item =>
    item.country.toLowerCase().includes(nameQuery.toLowerCase())
  );
}

function createAndCollectCountryItemWithContext(list,item) {
//const context = this; // e.g. { continent: 'Europe',region: 'Western Europe' }
  return list.concat(
    Object.assign({ country: item.Name },this)
  );
}
function createAndCollectCountryItemFromRegionWithContext(list,item) {
//const context = this; // e.g. { continent: 'Europe' }
  return list.concat(
    item.Countries.reduce(
      createAndCollectCountryItemWithContext.bind(
        Object.assign({ region: item.Name },this)
      ),[]
    )
  );
}
function createAndCollectCountryItemFromRegionAndContinent(list,item) {
  return list.concat(
    item.Regions.reduce(
      createAndCollectCountryItemFromRegionWithContext.bind({
        continent: item.Name,}),[]
    )
  );
}

const contriesGroupedByRegiosAndContinents = [{
  Name: 'Europe',Regions: [{
    Name: 'Western Europe',Countries: [{
      Name: 'United Kingdom',},{
      Name: 'Republic of Ireland',}],{
  Name: 'Asia',Regions: [{
    Name: 'Southeast Asia',Countries: [{
      Name: 'Indonesia',{
      Name: 'Philippines',{
  Name: 'Americas',Regions: [{
    Name: 'North America',Countries: [{
      Name: 'United States of America',{
      Name: 'Canada',}];

const listOfCountryItems = contriesGroupedByRegiosAndContinents.reduce(
  createAndCollectCountryItemFromRegionAndContinent,[]
);
console.log('listOfCountryItems ...',listOfCountryItems);


function queryCountryListByName(nameQuery) {
  return listOfCountryItems.filter(item =>
    item.country.toLowerCase().includes(nameQuery.trim().toLowerCase())
  );
}

console.log(
  "queryCountryListByName('  united  ') ...",queryCountryListByName('  united  ')
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

,

我们可以首先使用 Array.some 过滤大洲(对于地区和国家),然后循环匹配的大洲以记录结果:

// The string to search for.
let str = "United"

continents = [
{
     Name: 'Europe',Regions: [
       {
         Name: 'Western Europe',Countries: [
           {
             Name: 'United Kingdom'
           },{
             Name: 'Republic of Ireland'
           }
         ]
       }
     ]
  },{
     Name: 'Americas',Regions: [
       {
         Name: 'North America',Countries: [
           {
             Name: 'Canada'
           },{
             Name: 'United States of America'
           }
         ]
       }
     ]
  }
]

// Find all continents with matching countries
let matchingContinents = continents.filter(continent => continent.Regions.some(region => region.Countries.some(country => country.Name.includes(str))));
for(let continent of matchingContinents) {
    console.log(continent.Name);
    for(let region of continent.Regions) {
        console.log(" -> " + region.Name);
        for(let country of region.Countries) {
            if (country.Name.includes(str)) {
                console.log("   -> " + country.Name.replace(str,'**' + str + '**'));
            }
        }
    }
}

,

所以据我所知,您想获取大量对象并返回具有相同结构的过滤版本吗?如果是这样,你可以这样做。

const continents = [{
  Name: 'Europe',}];

const result = continents.map(con => {
  if(con.Regions.some(reg => reg.Countries.some(c => c.Name.startsWith('United')))){

    return {
      ...con,Regions: con.Regions.map(reg => {
        if(reg.Countries.some(c => c.Name.startsWith('United'))){
          return {
            ...reg,Countries: reg.Countries.filter(c => c.Name.startsWith('United'))
          }
        }
      }) 
    }
  }
});

console.log(result);
.as-console-wrapper { min-height: 100%!important; top: 0; }

显然,您希望将 'United' 替换为您的搜索词。