2

Given a number n , a minimum number min , a maximum number max , what is the most efficient method to determine

  1. Number n is or is not within range , inclusive of , min - max

  2. Number n does or does not contain duplicate numbers

  3. Efficiency meaning here that the method or set of methods requires the least amount of computational resources and returns either true or false in the least amount of time

  4. Context: Condition at if within a for loop which could require from thousands to hundreds of thousands of iterations to return a result; where milliseconds required to return true or false as to Number check could affect performance

At Profiles panel at DevTools on a collection of 71,3307 items iterated, RegExp below was listed as using 27.2ms of total 1097.3ms to complete loop . At a collection of 836,7628 items iterated RegExp below used 193.5ms within total of 11285.3ms .

Requirement: Most efficient method to return Boolean true or false given above parameters , within the least amount of time.

Note: Solution does not have to be limited to RegExp ; used below as the pattern returned expected results.


Current js utilizing RegExp re , RegExp.protype.test()

var min = 2
, max = 7
, re = new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
, arr = [81, 35, 22, 45, 49];

for (var i = 0; i < arr.length; i++) {
  console.log(re.test(arr[i]), i, arr[i])
    /*
      false 0 81 
      true 1 35
      false 2 22
      true 3 45
      false 4 49 
    */
}
guest271314
  • 1
  • 15
  • 104
  • 177
  • You are given three nos ...right? – Mathews Mathai Dec 28 '15 at 03:36
  • 1
    The regex is incorrect, you need to escape backslash. `new RegExp("[" + min + "-" + max + "](.)(?!=\\1)", "g")` – Tushar Dec 28 '15 at 03:37
  • @MathewsMathai _"You are given three nos ...right?"_ The number could be between two numbers; e.g., `25` up to `n` numbers , e.g., nine numbers `271314892` – guest271314 Dec 28 '15 at 03:40
  • @Tushar _"The regex is incorrect, you need to escape backslash. `new RegExp("[" + min + "-" + max + "](.)(?!=\\1)", "g")`"_ Where `\1` is reference to capture group `(.)` http://stackoverflow.com/questions/21880127/have-trouble-understanding-capturing-groups-and-back-references ? – guest271314 Dec 28 '15 at 03:43
  • @guest271314 Try `console.log(re);` and you'll see what I'm saying – Tushar Dec 28 '15 at 03:44
  • So the basic purpose is to check if `n` is in between `min` and `max` or not?...Am I right?? – Mathews Mathai Dec 28 '15 at 03:45
  • @MathewsMathai _"So the basic purpose is to check if n is in between min and max or not?...Am I right?? "_ Given `271314892` `false` should be returned , as both a) duplicate `1` , and `2` , contains numbers outside of range `2` through `7` – guest271314 Dec 28 '15 at 03:48
  • @Tushar The `RegExp` is not ideal though has returned expected results . Can create jsfiddle to demonstrate different outcomes using `\1` , `\\1` as back reference ? – guest271314 Dec 28 '15 at 03:54
  • You can use `var range = new RegExp("^[" + min + "-" + max + "]+$"); if(range.test(number) === false) { return false; }` early return. and then only check for duplicates. – Tushar Dec 28 '15 at 03:55
  • Check [fiddle](https://jsfiddle.net/tusharj/dqcpn2h0/), you want to use back-reference, so need to escape slash. – Tushar Dec 28 '15 at 03:56
  • @Tushar _"You can use var range = new RegExp("^[" + min + "-" + max + "]+$"); if(range.test(number) === false) { return false; "_ Can describe how approach would be different from, or more efficient than `RegExp` at Question ? – guest271314 Dec 28 '15 at 03:58
  • @Tushar Appear to return same result ? https://jsfiddle.net/dqcpn2h0/1/ – guest271314 Dec 28 '15 at 04:00
  • 1
    @guest271314 If there are chances that the numbers to test are out of given range, this will check if the digits are in the range and if not, it'll early return so saving the next backreference regex(which is costly). – Tushar Dec 28 '15 at 04:00

2 Answers2

2

Associative arrays approach:

This has the advantage of being easily understandable.

function checkDigits(min, max, n) {
    var digits = Array(10);                   // Declare the length of the array (the 10 digits) to avoid any further memory allocation
    while (n) {
        d = (n % 10);                         // Get last digit
        n = n / 10 >>0;                       // Remove it from our number (the >>0 bit is equivalent to compose(Math.floor, Math.abs))
        if (d < min || d > max || digits[d])  // Test if "d" is outside the range or if it has been checked in the "digits" array
            return false;
        else
            digits[d] = true;                 // Mark the digit as existing
    }
}

var min = 2
, max = 7
, arr = [81, 35, 22, 45, 49];

function checkDigits(min, max, n) {
    var digits = Array(10);                   // Declare the length of the array (the 10 digits) to avoid any further memory allocation
    while (n) {
        d = (n % 10);                         // Get last digit
        n = n / 10 >>0;                       // Remove it from our number (the >>0 bit is equivalent to compose(Math.floor, Math.abs))
        if (d < min || d > max || digits[d])  // Test if "d" is outside the range or if it has been checked in the "digits" array
            return false;
        else
            digits[d] = true;                 // Mark the digit as existing
    }
    return true;
}

for (var i = 0; i < arr.length; i++) {
  console.log(checkDigits(min, max, arr[i]), i, arr[i])
}

Binary mask approach:

This replaces the Array with an integer that is in effect used as an array of bits. It should be faster.

function checkDigits(min, max, n) {
    var digits = 0;                   
    while (n) {
        d = (n % 10);                         
        n = n / 10 >>0;
        if (d < min || d > max || (digits & (1 << d)))
            return false;
        else
            digits |= 1 << d;
    }
    return true;
}

function checkDigits(min, max, n) {
    var digits = 0;                   
    while (n) {
        d = (n % 10);                         
        n = n / 10 >>0;
        if (d < min || d > max || (digits & (1 << d)))
            return false;
        else
   digits |= 1 << d;
    }
    return true;
}

Explanation for binary mask approach:

1 << d creates a bit mask, an integer with the d bit set and all other bits set to 0.
digits |= 1 << d sets the bit marked by our bit mask on the integer digits.
digits & (1 << d) compares the bit marked by our bit mask with digits, the collection of previously marked bits.
See the docs on bitwise operators if you want to understand this in detail.

So, if we were to check 626, our numbers would go like this:

________n_____626_______________
           |
        d  |  6
     mask  |  0001000000
   digits  |  0000000000
           |
________n_____62________________
           |
        d  |  2
     mask  |  0000000100
   digits  |  0001000000
           |
________n_____6_________________
           |
        d  |  6
     mask  |  0001000000
   digits  |  0001000100
                 ^
               bit was already set, return false
lleaff
  • 4,249
  • 17
  • 23
0

Solution 1

test using regex

var min = 2;
var max = 7;
res = "";
arr = [81, 35, 22, 45, 49]
arr.push("");
regex=new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
var result = arr.reduce(function(a, b) {
  if (regex.test(a)) {
    res = res + a + " is true\n"
  } else {
    res = res + a + " is false\n"
  };
  return b
});
console.log(res)

The reduce method is different in a sense that it is like a generator function like in python (produces output on the fly)

Its simply loops through each elements in an array using a callback function. I cannot say how efficient is the reduce function.

Nevertheless consider two elements in the array

81                             35          
^
take this value            take the result
and do something           from the previous 
                           element and add it
                           to the result computed
                           for this element  

further information https://msdn.microsoft.com/en-us/library/ff679975%28v=vs.94%29.aspx

SOlution 2

Using list to store value and their boolean

var min = 2;
var max = 7;
res = [""];
arr = [81, 35, 22, 45, 49]
arr.push("");
regex=new RegExp("[" + min + "-" + max + "](.)(?!=\1)", "g")
var result = arr.reduce(function(a, b) {
  if (regex.test(a)) {
    res.push([a,true])
  } else {
    res.push([a,false])
  };
  return b
});
console.log(res)
repzero
  • 8,254
  • 2
  • 18
  • 40
  • `35` and `45` should return `true` ; `res` appear `undefined` ? – guest271314 Dec 28 '15 at 04:25
  • I use 2 and 7 for max value and I define var min=2 and var max =7..i make the edited – repzero Dec 28 '15 at 04:27
  • @reprezo Appear to return empty string from `.reduce()` ? Expected return value is `Boolean` `true` or `false` – guest271314 Dec 28 '15 at 04:35
  • output is log in the console...it returns "" which is the last element in the array.. the output is also stored in the variable "res"..you can print this....ensure you reset the variable res to "" before rerunning the iterator method – repzero Dec 28 '15 at 04:37
  • change console.log(result) to console.log(res) – repzero Dec 28 '15 at 04:42
  • _"change console.log(result) to console.log(res)"_ `35` and `45` should return `true` https://jsfiddle.net/h4xs0gft/1/ – guest271314 Dec 28 '15 at 04:43
  • all would be false since all values cannot be =>2 and <=7 – repzero Dec 28 '15 at 04:51
  • _"all would be false since all values cannot be =>2 and <=7"_ ?`true` returned for all numbers at https://jsfiddle.net/repzeroworld/ztebfL8e/ . `81`, `22` and `49` should return `false` ; see description of requirement at Question – guest271314 Dec 28 '15 at 04:52
  • my apologies....I had to interchange "true" and "false" back in the string due to the logics........https://jsfiddle.net/repzeroworld/xjnk1jaq/ – repzero Dec 28 '15 at 04:54
  • all values will be false.......unless you change your max to a higher number that a value in the array meets the condition – repzero Dec 28 '15 at 04:55
  • _"all values will be false.......unless you change your max to a higher number that a value in the array meets the condition"_ ? This is not correct. See text of Question at 1., 2. Each number appear returned as `false` at https://jsfiddle.net/repzeroworld/xjnk1jaq/ ? – guest271314 Dec 28 '15 at 04:56
  • Correct....81 is > 2 and not less than 7, 35 is > 2 and not less than 7,22 is > 22 and not less than 7 etc...all false – repzero Dec 28 '15 at 04:57
  • _"Correct....81 is > 2 and not less than 7, 35 is > 2 and not less than 7,81 is > 22 and not less than 7 etc...all false"_ No, not correct as to requirement of Question. E.g, `35` is actually two numbers – guest271314 Dec 28 '15 at 04:58
  • _"see edited answer"_ Can describe how updated solution is different from `js` at Question ? How would using `.reduce()` decrease time to return `true` or `false` using `.test()` . Why would `.reduce()` be necessary where `.test()` is used within callback of `.reduce()` ? – guest271314 Dec 28 '15 at 05:13
  • see edited answer as to how I understand the reduce function and from looking up the reference link – repzero Dec 28 '15 at 05:24
  • Requirement is to return `Boolean` in briefest duration. `js` at OP returns expected results using `RegExp` constructor and `RegExp.prototype.test()` without including third method `.reduce()` – guest271314 Dec 28 '15 at 05:26
  • I am focusing on the iteration aspect here...yes you can match digits but you still need an iterator or looping function to do the necessary ..isn't it?....my apologies if my approach is a little lack on the performance side but was it worth a try so you now know? – repzero Dec 28 '15 at 05:29
  • _"focusing on the iteration aspect here."_ Iteration aspect is not part of requirement. _"my apologies if my approach is a little lack on the performance"_ Performance is focus of Question; see description at original post at _"Requirement: Most efficient method to return Boolean true or false given above parameters , within the least amount of time."_ – guest271314 Dec 28 '15 at 05:33
  • So how will you know if you don't try it?You have the tools....DO you expect me to get 71,3307 Dev tools and do a performance test?....SO answers gave you an approach not only a solution...... – repzero Dec 28 '15 at 05:36
  • If a single number , `35` is passed to `.reduce()` using approach at Answer ; e.g., `[35].reduce(function(a, b) {})`, `res` does not appear to be returned as a `Boolean` value – guest271314 Dec 28 '15 at 05:44
  • 1
    Okay..I have added another solution where values and their corresponding booleans are stores in a list.....thats is about it for me...good nite..:D – repzero Dec 28 '15 at 05:58