Question

Does mathematica have something like "select any" that gets any element of a list that satisfies a criterion?

Was it helpful?

Solution 2

Well, the downside of Eric's answer is that it does execute OddQ on all elements of the list. My call is relatively costly, and it feels wrong to compute it too often. Also, the element of randomness is clearly unneeded, the first one is fine with me.

So, how about

SelectAny[list_List, criterion_] := 
 Catch[Scan[  If[criterion[#], Throw[#, "result"]] &, list]; 
  Throw["No such element"], "result"]

And then

SelectAny[{1, 2, 3, 4, 5}, OddQ]

returns 1.

I still wish something were built into Mathematica. Using home-brew functions kind of enlarges your program without bringing much direct benefit.

OTHER TIPS

If you just want to return after the first matching element, use the optional third argument to Select, which is the maximum number of results to return. So you can just do

Any[list_List, crit_, default_:"no match"] := 
    With[{maybeMatch = Select[list, crit, 1]},
        If[maybeMatch =!= {},
            First[maybeMatch],
            default]

Mathematica lacks a great way to signal failure to find an answer, since it lacks multiple return values, or the equivalent of Haskell's Maybe type. My solution is to have a user-specifiable default value, so you can make sure you pass in something that's easily distinguishable from a valid answer.

The Select function provides this built-in, via its third argument which indicates the maximum number of items to select:

In[1]:= Select[{1, 2, 3, 4, 5}, OddQ, 1]
Out[1]= {1}

When none match:

In[2]:= Select[{2, 4}, OddQ, 1]
Out[2]= {}

Edit: Oops, missed that nes1983 already stated this.

You can do it relatively easily with Scan and Return

fstp[p_, l_List] := Scan[ p@# && Return@# &, l ]

So

In[2]:= OddQ ~fstp~ Range[1,5]
Out[2]= 1
In[3]:= EvenQ ~fstp~ Range[1,5]
Out[3]= 2

I really wish Mathematica could have some options to make expressions evaluated lazily. In a lazy language such as Haskell, you can just define it as normal

fstp p = head . filter p

There's "Select", that gets all the elements that satisfy a condition. So

In[43]:= Select[ {1, 2, 3, 4, 5}, OddQ ]
Out[43]= {1, 3, 5}

Or do you mean that you want to randomly select a single matching element? I don't know of anything built-in, but you can define it pretty quickly:

Any[lst_, q_] :=
   Select[ lst, q] // (Part[#, 1 + Random[Integer, Length[#] - 1]]) &

Which you could use the same way::

 In[51]:= Any[ {1, 2, 3, 4, 5}, OddQ ]
 Out[51]= 3
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top