Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript most efficient function to find an item in an Array? and explain this tricky code

What can be the most efficient way to find an item in an array, which is logical and understood by a web developer?

I came across this piece of code:

var inArray = function(a, b, c, d) {
    for (c in b) d |= b[c] === a;
    return !!d
};

It works fine. Can someone please explain me the code?
I also came across an exact same question that might make mine as a duplicate. But my real question lies in explanation of the above code and why bitwise operator has been used into it.
Also, can there be a way without any for loop, or iteration to get index of an item in an Array?

like image 299
Om Shankar Avatar asked Dec 21 '22 11:12

Om Shankar


2 Answers

var inArray = function(a, b, c, d) {
    for (c in b) d |= b[c] === a;
    return !!d
};

That is some terrible code, and you should run away from it. Bitwise operators are completely unnecessary here, and c and d being parameters makes no sense at all (as Raymond Chen pointed out, the author of the code likely did it to safe space of declaring local variables -- the problem though is that if true is passed in for d the code is suddenly broken, and the extra parameters destroys any sense of understanding that glancing at the declaration would provide).

I'll explain the code, but first, here's a better option:

function inArray(arr, obj) {
    for (var i = 0; i < arr.length; ++i) {
        if (arr[i] === obj) {
            return true;
        }
    }
    return false;
}

Note that this is dependent on the array being an actual array. You could use a for (k in arr) type loop to generalize it to all objects.


Anyway, on to the explanation:

for (c in b) d |= b[c] === a;

This means that for every key in b (stored in c), we will check if b[c] === a. In other words, we're doing a linear scan over the array and checking each element against a.

d |= val is a bitwise or. The bits that are high in val will be set high in d. This is easier to illustrate in languages where bits are more exposed than in JS, but a simple illustration of it:

10011011
01000001
--------
11011011

It's just OR'ing each individual bit with the same location bit in the other value.

The reason it's an abuse here is that it convolutes the code and it depends on weird implicit casts.

x === y returns a boolean. A boolean being used in a bitwise expression makes little sense. What's happening though is that the boolean is being converted to a non-zero value (probably 1).

Similarly, undefined is what d will be. This means that d will be cast to 0 for the bitwise stuff.

0 | 0 = 0, but 0 | 1 = 1. So basically it's a glorified:

for (c in b) d = (d || (b[c] === a));

As for !!x that is just used to cast something to a bool. !x will take x, implicitly cast it to a bool and then negate it. The extra ! will then negate that again. Thus, it's likely implicitly casting to a bool (!!x being true implies that x is at least loosely true (1, "string", etc), and !!x implies that x is at least loosely false (0, "", etc).


This answer offers a few more options. Note though that all of them are meant to fallback to the native indexOf that will almost certainly be faster than anything we can code in script-land.

like image 86
Corbin Avatar answered Jan 17 '23 19:01

Corbin


This code is pretty poorly written, and barely readable. I wouldn't qualify it as "awesome"...

Here's a rewritten version, hopefully more readable:

function inArray (aElt, aArray) {
  var key;
  var ret = false;
  for (key in aArray)
    ret = ret || (aArray[key] === aElt);
  return ret;
}

The for loop seems like the most natural way to do that. You could do it recursively but that doesn't feel like the easiest approach here.

like image 21
Jonathan Protzenko Avatar answered Jan 17 '23 18:01

Jonathan Protzenko