Home > database >  React: filtering a dict of dict
React: filtering a dict of dict

Time:10-04

I have a dict of a dict that looks something like this:

{
    "Chain1": {
        Country1: [
           {name: "a", id: "1"},
           {name: "b", id: "2"}
        ]
     },
    "Chain2": {
        Country1: [
           {name: "c", id: "3"},
           {name: "d", id: "4"}
        ],
        Country2: [
           {name: "e", id: "5"},
           {name: "f", id: "6"}
        ]
     }

}

I would like to be able to filter on chain, country and name. But I'm a bit unsure how to filter further down than chain level. So far I've tried

  const filteredChains = Object.entries(dict).filter(
    ([chain, countries]) => {
      if (searchQuery.length > 0) {
        return chain.includes(searchQuery);
      } else {
        return chain;
      }
    }
  );

searchQuery is the input from a search bar that allows the user to filter what is being displayed. The user should be able to filter on chain, country and name. If the user types "j" I would expect the outcome to be that keys or values containing "j" only is shown.

Is it possible to expand on this one to filter further down? Or am I totally off?

CodePudding user response:

reduce over the object entries and for each key/value push them into a temporary array, and then merge that array with the accumulator for the next iteration.

const dict={Chain1:{Country1:[{name:"a",id:"1"},{name:"b",id:"2"}]},Chain2:{Country1:[{name:"c",id:"3"},{name:"d",id:"4"}],Country2:[{name:"e",id:"5"},{name:"f",id:"6"}]}};

function search(searchQuery) {

  // Making sure that we match against lowercase letters
  searchQuery = searchQuery.toLowerCase();

  if (searchQuery.length > 0) {

    // `reduce` over the object entries
    return Object.entries(dict).reduce((acc, [chain, country]) => {

      const temp = [];

      // If the chain key includes the query,
      // push it into the temp array
      if (chain.toLowerCase().includes(searchQuery)) {
        temp.push(chain);
      }
      
      const countryKey = Object.keys(country)[0];
      
      // If the country key includes the query,
      // push it into the temp array
      if (countryKey.toLowerCase().includes(searchQuery)) {
        temp.push(countryKey);
      }

      const names = Object.values(country)[0].map(obj => obj.name);

      // `filter` out the objects under country that
      // match the query and... push them into the temp array
      const filteredNames = names.filter(name => {
        return name.toLowerCase().includes(searchQuery);
      });
      
      temp.push(filteredNames);
    
      return [...acc, ...temp.flat()];
    
    }, []);

  }

  return null;

}

console.log(search('a'));
console.log(search('i'));
console.log(search('c'));
console.log(search(''));

CodePudding user response:

I assume, that you want the same object back, with only the countries in it, which collide with the search query by name or id.

var dict = {
  Chain1: {
    Country1: [
      { name: 'a', id: '1' },
      { name: 'b', id: '2' },
    ],
  },
  Chain2: {
    Country1: [
      { name: 'c', id: '3' },
      { name: 'd', id: '4' },
    ],
    Country2: [
      { name: 'e', id: '5' },
      { name: 'f', id: '6' },
    ],
  },
};


function filter(dict, searchQuery){
  if(!dict) return null;
  if(!searchQuery || searchQuery.length <=0) return dict;

  const result = {};
  for (chainKey in dict) {
    if (dict.hasOwnProperty(chainKey)) {
      const chains = dict[chainKey];
      for (countryKey in chains) {
        if (chains.hasOwnProperty(countryKey)) {
          const countries = chains[countryKey];
          const filteredCountries = countries.filter(
            (country) =>
              country.name.includes(searchQuery) ||
              country.id.includes(searchQuery)
          );
  
          if (filteredCountries.length) {
            result[chainKey] = {};
            result[chainKey][countryKey] = filteredCountries;
          }
        }
      }
    }
  }
  return result;
}

console.log(filter(dict, "a"));
console.log(filter(dict, "e"));
console.log(filter(dict, "f"));

  • Related