7
$\begingroup$

I'm having some trouble in the following exercise:

Find which elements of the list are prime numbers or divisible by 3.

list = Table[i^2 - 6 i - 1, {i, 0, 15}]

my attempt: Cases[list, Divisible[_,3]]. Mathematica didn't like this and I don't know how to write it correctly :/

For prime numbers, I used Cases[list, _?PrimeQ] and it gave me the right answer, but I can't imagine a way to use incorporate the "or" thing, except by using a If. Is there a more imperative way of doing this?

$\endgroup$
5
  • $\begingroup$ Welcome to Mathematica.SE! I hope you will become a regular contributor. To get started, 1) take the introductory Tour now, 2) when you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge, 3) remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign, and 4) give help too, by answering questions in your areas of expertise. $\endgroup$
    – bbgodfrey
    Aug 30, 2015 at 16:07
  • 1
    $\begingroup$ Select[] might be more straightforward for you. $\endgroup$ Aug 30, 2015 at 16:10
  • $\begingroup$ Cases[list,x_/;Or@@{Divisible[x,3],PrimeQ[x]}] $\endgroup$
    – N.J.Evans
    Aug 30, 2015 at 16:16
  • 1
    $\begingroup$ You can also define your test and use it as you did PrimeQ myTest[x]:=Or@@{Divisible[x,3],PrimeQ[x]}; Cases[list,_?myTest] $\endgroup$
    – N.J.Evans
    Aug 30, 2015 at 16:21
  • 1
    $\begingroup$ You might find the answers to (91180) and its linked duplicates of use. $\endgroup$
    – Michael E2
    Aug 30, 2015 at 16:38

4 Answers 4

16
$\begingroup$

Culling elements from lists may done several ways, such as with Cases, Select, and Pick. Cases and Select seem quite similar when culling elements from level 1. The documentation for Select shows that the following are equivalent:

Select[list, f]
Cases[list, x_ /; f[x]]

This, too, is equivalent:

Cases[list, _?f]

The functions Condition (/;) and PatternTest (?) are ways to restrict a pattern to match only expressions that both match the pattern and satisfy a (boolean) condition.

Let's turn to the exercise at hand: To use Cases to do the following.

Find which elements of the list are prime numbers or divisible by 3.

I like the expressiveness of Condition, if you read /; as "such that" or "that", so I'll try that. We can map the elements of the problem to elements of code if we mangle the order slightly:

(* Find            *)   Cases[
(* in the list     *)    list,
(* the elements    *)    x_ 
(* that are        *)     /;
(* either          *)     Or[
(*  prime or       *)      PrimeQ[x],
(*  divisible by 3 *)      Divisible[x, 3]
                         ]]

(*  {-6, -9, -9, -6, 6, 15, 39, 54, 71, 90, 111}  *)

Or more succinctly,

Cases[list, x_ /; PrimeQ[x] || Divisible[x, 3]]
$\endgroup$
6
  • 2
    $\begingroup$ Addendum: for a sufficiently long list, exploiting the short-circuit property of Or[] can be helpful: test for divisibility by $3$ first, since it's the easier test, and invoke the primality test only if that fails. So, x_ /; Divisible[x, 3] || PrimeQ[x] $\endgroup$ Aug 30, 2015 at 17:19
  • $\begingroup$ @Guesswhoitis. I'm not completely familiar with internals, but tests show PrimeQ is faster than Divisible[#, 3]& for small integers. (PrimeQ /@ Range@n vs. Divisible[#, 3] & /@ Range@n -- 30% faster when n < 10^6; 13% for n = 10^7, 10^8, though 10^8 seemed to exercise memory management.) $\endgroup$
    – Michael E2
    Aug 30, 2015 at 17:54
  • $\begingroup$ Huh, that's very odd (yet another case of slow new functions?). What if the less idiomatic Mod[#, 3] == 0 & was used instead? $\endgroup$ Aug 30, 2015 at 18:04
  • $\begingroup$ @Guesswhoitis. Divisible is 1/3 faster than Mod. $\endgroup$
    – Michael E2
    Aug 30, 2015 at 18:18
  • $\begingroup$ @Guesswhoitis. A partial explanation is that PrimeQ is really fast on even integers. On odd integers PrimeQ is faster (average 1 <= x <= n) up to n = 10^7 and then Divisible starts to edge it out. $\endgroup$
    – Michael E2
    Aug 31, 2015 at 1:52
4
$\begingroup$

Many possible approaches. One is

Union[Cases[list, _?PrimeQ], Cases[list, i_ /; Mod[i, 3] == 0]]
(* {-9, -6, 6, 15, 39, 54, 71, 90, 111} *)

Addendum

If, instead, you want the elements in order and with their corresponding i values

Flatten@Union[Position[list, _?PrimeQ], Position[list, i_ /; Mod[i, 3] == 0]]
list[[%]]
(* {2, 3, 5, 6, 8, 9, 11, 12, 13, 14, 15} 
   {-6, -9, -9, -6, 6, 15, 39, 54, 71, 90, 111} *)
$\endgroup$
0
2
$\begingroup$

Another way with the hint from @Guess who i is:

Select[list, Divisible[#, 3] &]~Union~Select[list, PrimeQ]
{-9, -6, 6, 15, 39, 54, 71, 90, 111}
$\endgroup$
2
  • $\begingroup$ I had Select[list, Divisible[#, 3] || PrimeQ[#] &] in mind, tho. $\endgroup$ Aug 30, 2015 at 17:05
  • $\begingroup$ @Guess who it is My first attempt, but today is sunday and it would not correctly work. Farther, I'm sure, I have typed the "t" in your name. I believe, it is tipped over. Sorry :-) $\endgroup$
    – user31001
    Aug 30, 2015 at 17:29
0
$\begingroup$

Most near your attempt:

Cases[list, _?(Divisible[#, 3] &)]

no x_ :p

what you write is a pattern, use _? make boolean into a pattern.

put together:

Cases[list, _?((Divisible[#, 3] || PrimeQ[#]) &)]
$\endgroup$

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.