# Detecting the existence of an element in a subarray with specific properties

If I have an array that looks like this:

testArray =
{{"StringOne", 3.444}, {"StringOne", 433}, {"StringOne", 1}, {"StringOne", 8},
{"StringOne", 1}, {"StringOne", 5}, {"StringOne", 2}, {"StringOne", 1},
{"StringOne", 9}, {"StringOne", 1}, {"StringTwo", 7.64}, {"StringTwo", 34},
{"StringTwo", 6}, {"StringTwo", 99}, {"StringTwo", 54}, {"StringTwo", 12.33},
{"StringTwo", 6}, {"StringTwo", 7}, {"StringTwo", 76}, {"StringTwo", 1}};


I want to quickly detect the existence of a subarray of the form: {"StringTwo", n} for all $n > k$ (for some real-valued $n$ and $k$).

How can I best do this?

-
Select & Cases – Sektor Jan 4 '14 at 14:23
Cases[testArray, {_, x_} /; x > 75] – bobthechemist Jan 4 '14 at 15:22

You can use

Position[testArray, "StringTwo"]
{{11, 1}, {12, 1}, {13, 1}, {14, 1}, {15, 1}, {16, 1}, {17, 1},
{18, 1}, {19, 1}, {20, 1}}


or can test for the presence of an element using

MemberQ[testArray, "StringTwo", 2]
True


Adding in the extra parameter $k$, we can test whether any of the second elements are larger than $k$ using:

Length[Select[
First@Rest@
Transpose[
testArray[[First@
Transpose@Position[testArray, "StringTwo"]]]], # > k &]] > 0


Replace k by 9 and you get True. Replace k by 100 and you get False as expected. Of course you would probably want to make this into a function for easy use. Somewhat more concisely, you could use:

Select[testArray, (#[[1]] == "StringTwo") && (#[[2]] > 9) &] != {}


which directly checks if there are any elements of testArray with first element equal to "stringTwo" and second element that is > k.

-
I'm just trying to quickly determine if there exists some element in that larger array of the form: {"StringTwo",n} where "n" is some integer or real number > k (an arbitrarily specifiable threshold). – user11565 Jan 4 '14 at 13:21
I'm just looking for a way to ask if an element like this (i.e. a subarray like this) exists in testArray, with a TRUE or FALSE result. I need to do this efficiently. – user11565 Jan 4 '14 at 13:22
Then you don't really mean "for all n", you mean "for some n", since it will never be true that an element exists for all n. – bill s Jan 4 '14 at 13:27
I meant "for all n > k" in the question description, but you're right, I wasn't clear. – user11565 Jan 4 '14 at 13:38

Try

k = 10;
Cases[testArray, {"StringTwo", n_} /; n > k, 1, 1] != {}

(* True *)


Since you are only testing for existence you want to use a method that short-cuts, that is, returns True as soon as it finds any instance of what you are looking for. The third and fourth argument of Cases specify to only search the 1st level of the list and return the first instance it finds. The search pattern is written to find a list with a literal "StringTwo" followed by a pattern n subject to the constraint that n>k. Here is a tutorial on the use of constraints with patterns.

-

For True or False result Catch and Throw is a good option, because it breaks the evaluation when the condition match. Here is:

memberQ[list_List,string_String,value_?NumberQ]:=
Catch[If[#[[1]]==string&&#[[2]]>value,Throw[#]]&~Scan~list]=!=Null


Let's test it

memberQ[testArray,"StringTwo",5]


True

## Time Performance

bigTestArray=Join @@ Table[testArray, {i, 1, 100000}]

MemberQ[bigTestArray, {"StringTwo", x_} /; x > 5] // AbsoluteTiming
memberQ[bigTestArray,"StringTwo",5]//AbsoluteTiming
Cases[bigTestArray, {"StringTwo", n_} /; n > 5, 1, 1] != {}//AbsoluteTiming
Select[bigTestArray, (#[[1]] == "StringTwo") && (#[[2]] > 5) &] != {} // AbsoluteTiming

{0.000036,True}
{0.000081,True}
{0.017640,True}
{3.542719,True}

-
For me, MemberQ[bigTestArray, {"StringTwo", x_} /; x > 5] // AbsoluteTiming is twice as fast as memberQ. – C. E. Jan 5 '14 at 1:42
tks @Anon, answer improved. – Murta Jan 5 '14 at 13:24