Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript nested object filtering create new object

Suppose I have object

let x = { "people" :{
             "Sally": "value",
             "Bob" : "other value"
                    },
          "cars" :{
             "Saab" : "this",
             "Chevy": "that"
                    },
           "trees":{
              "Birch" : "what",
              "Oak" : "where"
                    }
                }

I want to search, so if I searched for "S" I'd get back an array that was

{ "people" :{
     "Sally": "value",
          },
  "cars" :{
     "Saab" : "this",
          }
}

And if I searched for "b" I'd get:

{ "people" :{
        "Bob" : "other value"
           },
   "trees":{
        "Birch" : "what",
           }
}

or "bo" would return

    { "people" :{
        "Bob" : "other value"
     }

And if I searched "e" I'd get

{  "cars" :{
             "Chevy": "that"
            }
}

Note that the "people" and "trees" isn't caught by the search for 'e'.

The strut will be of a fixed depth, and we only ever want to catch keys that match the filter and don't have children (we're also not interested in values that match, just keys).

Adding npm dependencies is acceptable.

Attempted solution:

    filteredList(unfiltered,searchVal) {
  return unfiltered.filter(search=> {
    return search.toLowerCase().includes(searchVal.toLowerCase())
  })
}

Obviously there's more to it, but I'm not sure which direction to proceed.

like image 443
David Little Avatar asked Mar 01 '26 03:03

David Little


2 Answers

This is a basic attempt. It's seems work quite fine but I'm very sure that it may be possible to make even better. But I don't know how.

let x = {
  "people": {
    "Sally": "value",
    "Bob": "other value"
  },
  "cars": {
    "Saab": "this",
    "Chevy": "that"
  },
  "trees": {
    "Birch": "what",
    "Oak": "where"
  }
}

let search = "B";

let result = {};

for (let key in x) {
  let tmp = {};
  for (let subKey in x[key]) {
    if (subKey.includes(search)) { // Use startsWithif you want even substring that aren't at the beginning
      tmp[subKey] = x[key][subKey];
    }
    if (Object.keys(tmp).length > 0) {
      result[key] = Object.assign({}, tmp);
    }
  }
}

console.log(result)

If you want an arbitrary deep, you should try with some kind of recursion, but that will be more complex.

like image 139
Ender Look Avatar answered Mar 02 '26 17:03

Ender Look


Here's a solution that uses the lodash library. Lodash has a number of super useful methods for object manipulation, in this case _.pickBy and _.mapValues can be used to filter your nested object.

Example:

let x = {
  "people": {
    "Sally": "value",
    "Bob": "other value"
  },
  "cars": {
    "Saab": "this",
    "Chevy": "that"
  },
  "trees": {
    "Birch": "what",
    "Oak": "where"
  }
}

function search(query) {
    query = query.toLowerCase();
    const matched = _.mapValues(x, v => _.pickBy(v, (_, k) => k.toLowerCase().includes(query)));
    return _.pickBy(matched, v => Object.keys(v).length)
}

console.log(search("S"))
console.log(search("b"))
console.log(search("bo"))
console.log(search("e"))
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
like image 32
CRice Avatar answered Mar 02 '26 15:03

CRice



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!