8
$\begingroup$

This will probably be a very easy question, yet although I did find a relatively similar one, I couldn't use the answers there to solve my problem (I'm still a novice). I'm simulating 10 blocks of pairs of dice tosses with

RandomChoice[Range[6], {10, 2}]

I would like to select those (and only those) sub-lists that contain at least one number greater than 4 (so I want {1,5} but not {4,4}, etc.). I tried both Cases and Select, but without any success.

For example, I was hoping this might work:

Select[RandomChoice[Range[6], {10, 2}, {___, # > 4 &, ___}]

But it doesn't. Any help would be greatly appreciated.

$\endgroup$
7
  • 2
    $\begingroup$ You might be interested in this thread. $\endgroup$ Oct 17, 2015 at 3:15
  • $\begingroup$ Yes, very impressive indeed. Many thanks! $\endgroup$
    – Mik
    Oct 17, 2015 at 3:24
  • $\begingroup$ There are things to do after your question has been answered. Its good to stay vigilant some time after you get the first answer as its likely that better approaches may come later improving over a previous reply and experienced users may point to caveats. Therefore, new users may wait 24 hours before voting the deserving answers and accepting the best one for you. (Links contain useful information) $\endgroup$
    – rhermans
    Oct 18, 2015 at 12:53
  • $\begingroup$ @rhermans: Thanks for the advice. I did vote all of the answers up, but that's because I checked each of them out, and they all solved the problem that motivated this post. I haven't noticed the accept feature, thanks for pointing that out as well. I also wasn't aware that one is not supposed to say "thank you" to someone who helps, so sorry for that. (Having read the guidelines, I can't help feeling that this comment itself is also inappropriate.) $\endgroup$
    – Mik
    Oct 18, 2015 at 14:07
  • $\begingroup$ Chatty comments are not encouraged, that is true, but we are all still humans. There is no need to apologize, I was just evangelizing "best practices" with a "prerecorded message" and you did nothing wrong. $\endgroup$
    – rhermans
    Oct 18, 2015 at 14:11

6 Answers 6

6
$\begingroup$

Just to add a solution using ContainsAny and Cases

EDIT: Updated in 10.3: MemberQ This is the clearest to read.

Data

data = RandomInteger[{1, 6}, {16, 2}]
(* {{2, 6}, {1, 3}, {5, 2}, {1, 3}, {2, 4}, {3, 1}, {6, 2}, {4, 
  5}, {4, 4}, {5, 1}, {4, 4}, {4, 5}, {4, 2}, {2, 1}, {6, 3}, {5, 2}} *)

hugedata = RandomInteger[{1, 6}, {1000000, 2}];

ContainsAny

Select[data, ContainsAny[{5, 6}]]

Or

Select[data, ContainsAny[#, {5, 6}] &]
(* {{2, 6}, {5, 2}, {6, 2}, {4, 5}, {5, 1}, {4, 5}, {6, 3}, {5, 2}} *)

Speed: Quite slow

First@Timing[Select[hugedata, ContainsAny[#, {5, 6}] &];]
(* 11.0761 *)

MemberQ

MemberQ, updated to operator form in Mathematica 10.3

Select[data, MemberQ[Alternatives @@ {5, 6}]]
(* {{2, 6}, {5, 2}, {6, 2}, {4, 5}, {5, 1}, {4, 5}, {6, 3}, {5, 2}} *)

Speed: Decent but not the fastest.

First@
 Timing[Select[hugedata, MemberQ[Alternatives @@ {5, 6}]];]
(* 1.93441 *)

Cases

Using Cases

Cases[data, {_, 5} | {_, 6} | {5, _} | {6, _}]

Or equivalently but more general

Cases[data, Alternatives @@ Permutations[{_, (5 | 6)}, {2}]]

Speed: This one is fast!

First@
 Timing[Cases[hugedata, {_, 5} | {_, 6} | {5, _} | {6, _}];]
(* 0.421203 *)

UPDATE

Slower but "cleaner" using OrderlessPatternSequence

Cases[data, {OrderlessPatternSequence[_, (5 | 6)]}]
$\endgroup$
1
  • $\begingroup$ Simple and elegant, especially the one using Permutations. Thanks! $\endgroup$
    – Mik
    Oct 17, 2015 at 13:55
11
$\begingroup$

This is good for big list

l = RandomInteger[100, {1000000, 2}];

Timing[Pick[l, Times @@@ UnitStep[4 - l], 0];]
(*{0.546875, Null}*)

Update

For better timing also try this:

Timing[Pick[l, Min /@ UnitStep[4 - l], 0];] 
(*{0.046875, Null}*)
$\endgroup$
1
  • $\begingroup$ this is neat +1 :) $\endgroup$
    – ubpdqn
    Oct 17, 2015 at 7:54
9
$\begingroup$

One way to do this:

BlockRandom[SeedRandom[42, Method -> "MersenneTwister"]; (* for reproducibility *)
            p = RandomChoice[Range[6], {10, 2}];
            q = Select[p, Or @@ Thread[# > 4] &]];

p
   {{5, 1}, {1, 4}, {6, 6}, {4, 3}, {3, 4}, {2, 6}, {4, 3}, {5, 3},
    {2, 2}, {3, 1}}

q
   {{5, 1}, {6, 6}, {2, 6}, {5, 3}}
$\endgroup$
2
  • $\begingroup$ +1 for pointing out BlockRandom $\endgroup$
    – Bob Hanlon
    Oct 17, 2015 at 3:18
  • 1
    $\begingroup$ @Bob, I do like using that function a lot; I often answer questions here during lulls in whatever I'm working on, and I quite like being able to seed the PRNG temporarily, without the seeding affecting the current PRNG state my other computations are depending on. $\endgroup$ Oct 17, 2015 at 3:30
7
$\begingroup$
SeedRandom[42, Method -> "MersenneTwister"];

p = RandomChoice[Range[6], {10, 2}]

(*  {{5, 1}, {1, 4}, {6, 6}, {4, 3}, {3, 4}, {2, 6}, {4, 3}, {5, 3}, {2, 
  2}, {3, 1}}  *)

Select[p, Max @@ # > 4 &]

(*  {{5, 1}, {6, 6}, {2, 6}, {5, 3}}  *)

As J.M. is back points out in his comment below, this can be written more concisely as

Select[p, Max@# > 4 &]

(*  {{5, 1}, {6, 6}, {2, 6}, {5, 3}}  *)
$\endgroup$
1
  • $\begingroup$ You could just do Select[p, Max[#] > 4 &]; then your answer will be officially nicer than mine. ;) $\endgroup$ Oct 17, 2015 at 3:29
7
$\begingroup$
func[lst_] := Pick[lst, Max /@ Sign[lst - 4], 1]

Update with some timings

Test functions:

algohi1[r_] := Pick[r, Times @@@ UnitStep[4 - r], 0];
u[r_] := Pick[r, Max /@ Sign[r - 4], 1];
algohi2[r_] := Pick[r, Min /@ UnitStep[4 - r], 0];

Using RepeatedTiming as informed to me by Silvia:

rc = RandomChoice[Range[6], {1000000, 2}];
RepeatedTiming[#[rc]][[1]] & /@ {algohi1, u, algohi2}

yielded: {0.84, 0.0731, 0.0767}

Original answer

This was just to play and using "distance"

df[x_, y_] := Min[Abs[x - y]]
    fun[x_] := Pick[x, df[#, {6, 6}] <=1 & /@ x]
    rc = RandomChoice[Range[6], {20, 10, 2}];
    col[x_] := Style[x, Red] /; df[x, {6, 6}] <= 1
    col[x_] := x
    Grid[Map[col /@ # &, rc]]

enter image description here

Timings Using Mr.Wizard's timeAvg:

SetAttributes[timeAvg, HoldFirst]

timeAvg[func_] := 
 Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 
   15}]

and inspired by Algohi's answer:

r = RandomChoice[Range[6], {1000000, 2}];
timeAvg[fun@r;]
timeAvg[Pick[r, Times @@@ UnitStep[4 - r], 0];]
timeAvg[Pick[r, Max /@ Sign[r - 4], 1];]

yield: 5.45313, 0.703125, 0.06 respectively.

$\endgroup$
6
  • 1
    $\begingroup$ There is a RepeatedTiming in 10.1 now. $\endgroup$
    – Silvia
    Oct 17, 2015 at 13:42
  • $\begingroup$ @Silvia thank you I did not know this...always learning something :) $\endgroup$
    – ubpdqn
    Oct 17, 2015 at 13:55
  • $\begingroup$ Your method is pretty fast! (+1 already :) $\endgroup$
    – Silvia
    Oct 17, 2015 at 13:57
  • $\begingroup$ @ubpdqn can you add the updated solution in my answer to your timing comparison. Thanks $\endgroup$ Oct 17, 2015 at 14:20
  • $\begingroup$ @Algohi midnight here...will aim to do in am :) $\endgroup$
    – ubpdqn
    Oct 17, 2015 at 14:25
4
$\begingroup$

Maybe this:

Select[RandomChoice[Range[6], {10, 2}], First[#] > 4 || Last[#] > 4 &]
$\endgroup$
2
  • $\begingroup$ I think this wins for me in terms of comprehensibility. Cheers! $\endgroup$
    – Mik
    Oct 17, 2015 at 3:40
  • 1
    $\begingroup$ Or replace "First[#] > 4 || Last[#] > 4 &" by "Max[#]>4&", which is a bit easier to read and interestingly quite a bit faster (1.375 sec. rather than 2.125 sec. on hugedata as defined by rhemans). $\endgroup$ Oct 21, 2015 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.