# Check if a scalar falls within the range given by sub-arrays of a matrix

I have a rank 3 matrix:

r = {{{1, 10}, {19, 71}, {111, 159}}, {{1, 5}, {25, 63}, {118, 132}, {164, 185}}, {{1, 19}, {28, 49}, {157, 203}}};


and each of the sub-arrays above represents a range. No two sub-arrays in a given row has any overlap.

I want to check if given i of r[[i]] and a scalar x, I want to check if any of the sub-arrays have x within their range.

e.g. if i =2 and x=175 is TRUE because {164,185} has it, but x=75 is FALSE since none of the {1, 5}, {25, 63}, {118, 132}, {164, 185} has it.

I do not want to use MapThread and use compilable functions, UnitStep if possible.

-
I'm happy to be able to quickly answer this one for you. –  Mr.Wizard Aug 6 at 21:44
@Mr.Wizard Thank you. Look for more brain picking from me on SE. +1 –  brama Aug 6 at 21:50

First convert your sub-arrays to Interval format:

r2 = Interval @@@ r;


Then you may use IntervalMemberQ:

i = 2;
x = 175;

IntervalMemberQ[r2[[i]], x]

True


It will be difficult to compile a complete function for your problem because the input will need to be a rectangular tensor, and your data is not:

TensorQ[r]

False


You could compile a function to check an individual sub-array but that is essentially what IntervalMemberQ already is I imagine. If you find this test to be the performance bottleneck in your code you should post the context in which you are using it (in a new question) so that other recommendations might be made.

-
Another gem!!...but is IntervalMemberQ compilable? –  brama Aug 6 at 22:04
@brama Why would it need to be compilable? It is already a fast System function. Are you creating code for export to another language, e.g. C? –  Mr.Wizard Aug 6 at 22:18
I was planning to use it in an already compiled code. Unfortunately, NoneTrue is not compilable. If I do not find any compilable functions to do it, I might still go with IntervalMemberQ and uncompilable function if it performs better than compilable with MapThread. –  brama Aug 6 at 23:24

Edit: If you have V10, then:

f[r_, i_, scalar_] := AnyTrue[r[[i]], #[[1]] <= scalar <= #[[2]] &]


Otherwise,

f[r_, i_, scalar_] := ! VectorQ[r[[i]], Not[#[[1]] <= scalar <= #[[2]]] &]


Check:

f[r, 2, 175]


True

f[r, 2, 75]


False

-
Echo my comment to Algohi: it is highly inefficient to expand intervals to an explicit range of numbers. It also works only for integer x values, assuming a step size of 1. –  Mr.Wizard Aug 6 at 22:24
@Mr.Wizard. I agree. I was just working on a fix. –  RunnyKine Aug 6 at 22:25
@Mr.Wizard. See edit. –  RunnyKine Aug 6 at 22:49
Sorry to keep criticizing, but the problem with Or @@ is that you test every interval even if the first one is a match. This is why I used NoneTrue. +1 for making this a function however. –  Mr.Wizard Aug 6 at 23:11
@Mr.Wizard, your criticisms are appreciated and thanks. I'll keep working on it. –  RunnyKine Aug 6 at 23:27

x = 175;
Map[MemberQ[#, x] &, Apply[Range, r, {2}], {2}]

(*{{False, False, False}, {False, False, False, True}, {False, False,
True}}*)

-
This is much less efficient than it could be as you expand each interval rather than merely comparing end points. See my updated answer for how one might approach this. –  Mr.Wizard Aug 6 at 22:23
Pick[r, ! Cases[#, {x_, y_} /; x <= 175 <= y] == {} & /@ r]


If you just want to check if the number belongs to any interval in a row of r:

!Cases[#,{x_,y_}/;x<=175<=y]=={}&/@r
(* {False,True,True} *)

!Cases[#,{x_,y_}/;x<=75<=y]=={}&/@r
(* {False,False,False} *)

-