简体   繁体   中英

Get an array of objects that match condition in nested object

I have an array of objects something like this:

array_ = [
    {id: "id_one", name:"name_one"},
    {id: "id_two", name:"name_two"},
    {
        id:"id_three",
        data: [
            {data:0,name:"name_three"},
            {data:0,name:"name_four"}
        ]
    },
    {id: "id_four", name: "name_five"}
]

You can see that some are simple objects, but some have an array of sub-objects, but each one has the key name .

Now, what I want to do is find all the objects with a name field that includes a string.

For example, if I want to find all the objects with name values which include the string "name_" , it should return an array of all the objects in array_ .

But if I test for the string "name_t" , I'd want it to return an array containing the id:two object and the object with id:three, data[0].

Essentially, a search bar.

But I want it to only search for the beginning of the string. So as above, "name_" would return all, but "ame_" would return none.

I don't know if that made any sense, but if It did, I hope someone can help me with this.

Minimal Code:

HTML:

<body>
    <input id="text-input" type="text"
</body>

JavaScript (I'm using jQuery):

$('#text-input').on('input', () => {
        let inputValue = $('#text-input').val()

        function  deepSearch (object, key, predicate) {
            if (object.hasOwnProperty(key) && predicate(key, object[key]) === true) return object

            for (let i = 0; i < Object.keys(object).length; i++) {
              if (typeof object[Object.keys(object)[i]] === "object") {
                let o = deepSearch(object[Object.keys(object)[i]], key, predicate)
                if (o != null) return o
              }
            }
            return null
        }
        let object_ = deepSearch(array_, "name", (k, v) => v.includes(inputValue))
        console.log(object_)


    })

This is using a functions I found at this question

This function is almost what I need.

However, it returns the first object with containing the string, whereas I want an array containing all objects that match.

No need for jQuery, necessarily. You can write a recursive function that applies a predicate callback to every node in the tree and keeps the ones that match, flattening arrays as it walks back up the tree. The predicate lets you specify any condition for matching and gives the caller flexibility.

 const findNested = (children, predicate, childProp="data") => { const found = []; for (const node of children) { if (node[childProp]) { found.push(...findNested(node[childProp], predicate)); } if (predicate(node)) { found.push(node); } } return found; }; const tree = [ {id: "id_one", name:"name_one"}, {id: "id_two", name:"name_two"}, { id:"id_three", data: [ {data:0,name:"name_three"}, {data:0,name:"name_four"} ] }, {id: "id_four", name: "name_five"} ]; const predicate = e => e.name && e.name.startsWith("name_t"); console.log(findNested(tree, predicate));

Try this function which recursively searches the object and appends them to an array:

function search(arr, str) {
    var ret = [];
    for (var i = 0; i < arr.length; i ++) {
        if (typeof arr[i].name == "string" && arr[i].name.startsWith(str)) {
            ret.push(arr[i]);
        } else if (arr[i].data instanceof Array) {
            ret = ret.concat(search(arr[i].data, str));
        }
    }
    return ret;
}

search(array_, "name_t"); // array with the 2 matched objects

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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