4

Task

You're given an array of integers a and two integers x and y. Count the number of elements in the array such that `x ≤ a[i] ≤ y, where i is the 0-based index of the element.

Code Limit

Less than 48 characters.

Example

For a = [2, 5, 6, 7, 1, 3, 4, 11, 56, 49], x = 1 and y = 7, the output should be 7.

elements 2, 5, 6, 7, 1, 3, 4 should be counted.

I have tired filter, reduce and can't think any other possible way without making it longer than 48 characters.

Here's through using filter

checkRange=(a,x,y)=>a.filter(i=>i>=x&&i<=y).length

Using reduce

checkRange=(a,x,y)=>a.reduce((c,i)=>i>=x&&i<=y?++c:c,0);

Function call example

a =[95,92,27,55,55,20,40,8,7,45,87,14,44,35,64,84,95,85,69,47,53,49,95,54,97,7,67,31,76,97,7,24,82,61,10,34,34,85,66,96,65,2,84,4,68,74,46,50]
    x = 64
    y = 76

checkRange(a,x,y) // Expected: 8

I'm getting over 50+ characters so far....and I need to reduce them to 47.

Some Hints so far...

  • Use another shorter method
  • Count the index-values, rather than using length.
  • Don't need <= or >=, only need ==

I have gotten these from https://www.codewars.com/kata/one-line-task-check-range/discuss/javascript

Abubakar101
  • 121
  • 2
  • 6
  • Fun question! I'm at 48 chars using other tips from the thread, but I used > and <. Any enlightenment on the `==` tip if you happen to know it? I'm searching "bitwise between" and similar without result. – ggorlen Oct 09 '18 at 22:23
  • Here's where I'm at: `checkRange=(a,x,y)=>a.map(e=>ey||i++,i=0)|i` – ggorlen Oct 09 '18 at 22:48

1 Answers1

6

This one passes all the test on codewars (thanks @ggorlen for the hint):

a = [2, 5, 6, 7, 1, 3, 4, 11, 56, 49];
x = 1;
y = 7;
checkRange=(a,x,y)=>a.map(v=>i+=x>v==v>y,i=0)|i;
console.log(checkRange(a,x,y));

It works by setting up a counter (i) using the thisValue parameter to Array.map which replaces all the values in a with the count of how many values pass the test x>v==v>y (by using i+=x>v==v>y - in an arithmetic context a boolean value is considered to be 1 (true) or 0 (false)). So for the sample array, we get [1,2,3,4,5,6,7,7,7,7] (although the only part we are actually interested in is the value of i). The test computes whether x>v and v>y are both the same, which can only be true when they are both false, which implies x<=v and v<=y which is our desired end condition. Finally the |i attempts to bitwise or an array with i which is equivalent to just i since an array in that context == NaN, and NaN bitwise OR'ed with a number returns that number.

Note that in the special case where a has one number in it, the output from map will be either [0] or [1] and this will successfully be converted to 0 or 1 for the purpose of the bitwise OR. In this case that number will be the same as i (since the output of map is an array of i values), so again the result of the bitwise OR will be i as desired. For example:

a = [2];
x = 1;
y = 7;
checkRange=(a,x,y)=>a.map(v=>i+=x>v==v>y,i=0)|i;
console.log(checkRange(a,x,y));

a = [49];
console.log(checkRange(a,x,y));
Nick
  • 138,499
  • 22
  • 57
  • 95
  • Needs elaboration. What's `i+=` doing in this? It seems that it's concating true or false values? Then shouldn't we take "more than equal" operation into consideration? Why does having just `>` satisfy? And then how does the last `i` work? – Abubakar101 Oct 09 '18 at 23:26
  • @Abubakar101 added explanation. Hopefully it is clear. – Nick Oct 09 '18 at 23:35
  • I understood. Thanks for the explanation and I'd never assumed that concating the `true` Boolean would increment the number value. – Abubakar101 Oct 09 '18 at 23:52
  • 1
    @Abubakar101 it's not a concat, it's an addition (when `i` is initially assigned it is as a number (`i=0`)) and so the boolean becomes either 0 or 1 in that context. – Nick Oct 09 '18 at 23:53
  • can someone explain how a bitwise OR operator operates on the array? – Kerron Sep 27 '21 at 16:48
  • 1
    @Kerron JS attempts to convert the array output by `map` to an integer for the purpose of the bitwise OR. It first does that by calling the `toString()` method, which in this case returns `"1,2,3,4,5,6,7,7,7,7"`. It then attempts to convert that to a number, which returns `NaN` as it cannot be converted because of the commas. NaN bitwise OR'ed with a number (in this case `7`) returns that number. – Nick Sep 28 '21 at 00:01
  • @Nick haha, brilliant explanation - thank you! Is there any resource you found this on that you can point me to? Nothing I found was this explanatory/in-depth. – Kerron Sep 28 '21 at 00:20
  • 1
    @Kerron there's a bunch of stuff in the ECMAScript spec (starting from [here](https://tc39.es/ecma262/#sec-numeric-types) or [here](https://tc39.es/ecma262/#sec-binary-bitwise-operators) that if you follow deep enough down the rabbit hole you will get to the same result. – Nick Sep 28 '21 at 00:31