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$
  • 2
    $\begingroup$ You might be interested in this thread. $\endgroup$ – J. M. is away Oct 17 '15 at 3:15
  • $\begingroup$ Yes, very impressive indeed. Many thanks! $\endgroup$ – Mik Oct 17 '15 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 '15 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 '15 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 '15 at 14:11
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$
  • $\begingroup$ Simple and elegant, especially the one using Permutations. Thanks! $\endgroup$ – Mik Oct 17 '15 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$
  • $\begingroup$ this is neat +1 :) $\endgroup$ – ubpdqn Oct 17 '15 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$
  • $\begingroup$ +1 for pointing out BlockRandom $\endgroup$ – Bob Hanlon Oct 17 '15 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$ – J. M. is away Oct 17 '15 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$
  • $\begingroup$ You could just do Select[p, Max[#] > 4 &]; then your answer will be officially nicer than mine. ;) $\endgroup$ – J. M. is away Oct 17 '15 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$
  • 1
    $\begingroup$ There is a RepeatedTiming in 10.1 now. $\endgroup$ – Silvia Oct 17 '15 at 13:42
  • $\begingroup$ @Silvia thank you I did not know this...always learning something :) $\endgroup$ – ubpdqn Oct 17 '15 at 13:55
  • $\begingroup$ Your method is pretty fast! (+1 already :) $\endgroup$ – Silvia Oct 17 '15 at 13:57
  • $\begingroup$ @ubpdqn can you add the updated solution in my answer to your timing comparison. Thanks $\endgroup$ – Algohi Oct 17 '15 at 14:20
  • $\begingroup$ @Algohi midnight here...will aim to do in am :) $\endgroup$ – ubpdqn Oct 17 '15 at 14:25
4
$\begingroup$

Maybe this:

Select[RandomChoice[Range[6], {10, 2}], First[#] > 4 || Last[#] > 4 &]
$\endgroup$
  • $\begingroup$ I think this wins for me in terms of comprehensibility. Cheers! $\endgroup$ – Mik Oct 17 '15 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$ – Jacques Cremer Oct 21 '15 at 14:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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