简体   繁体   中英

How to check if item exists within nested array

Let me begin with the statement that no, this question is not a duplicate of How can I check If a nested array contains a value? . I read that question first and determined that it does not fit my requirements. This problem involves an array X of arrays Y , where the search needs to happen in any Y without knowing which Y to search beforehand.


I currently have an algorithm as part of an "app" that does the following:

const controls = [
    ["f", "Foo the bar", function(unused){ ... }],
    ["b", "Bar the baz", function(ev){ ... }],
    ["?", "Show this help", function(unused){ ... }],
    ...
];
...
function ev_keyboard(ev){
    controls.forEach(function([key, unused, callback]){
        if(ev.key === key)
            callback(ev);
    });
}

This makes it possible for the user to add their own key-bindings by just modifying controls . Super easy to understand and extend for the user who wants a little more.

This is all well and good, but I'm slightly annoyed with the knowledge that it will continue skipping down the bindings even after finding the matching bind and executing its callback. Because, you know, forEach . So, I tried improving it.

I could just go old school and use a for loop:

for(let i = 0; i < controls.length; i++)
    if(controls[i][bind_key] === ev.key)
        return controls[i][bind_callback](ev);

Or perhaps more appropriately:

function find_bind(key){
    for(let i = 0; i < controls.length; i++)
        if(controls[i][bind_key] === key)
            return controls[i][bind_callback];

    return ()=>null;
}
...
function ev_keyboard(ev){
    find_bind(ev.key)(ev);
}

But I'm told that for loops are bad for some reason (if I had to guess, it's because of JS's esoteric lock-up behavior when in an infinite loop). So here's the alternate fix:

function ev_keyboard(ev){
    let match = keyboard_controls.indexOf(ev.key); // what am I doing...

    if(match !== -1)
        keyboard_controls[match][bind_callback](ev);
}

You probably caught the error before even getting to the self-aware comment. I did, too. The problem is that there's a layer of separation here, and changing the structure to something like...

{
    "f": ["Foo the Bar", function(unused){ ... }],
    ...
}

...seems a little sloppy to me.

Is there some kind of efficient, non-library, idiomatic, recursive equivalent to indexOf for this purpose? Should I go with the C-like for loop search-and-return? Is it even worth worrying about since there are only so many bindings a reasonable person would make/be willing to remember? Or should I just stick with the original approach in spite of the previous sentence?

Use Array's find method. See MDN Array.prototype.find

function ev_keyboard(ev) {
    const control = controls.find(([key, unused, callback]) => ev.key === key)
    // control could be undefined
    if (control && typeof control.callback === 'function') {
        control.callback()
    }
}

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