1
$\begingroup$

How can I find in a list l the positions of all elements satisfying a boolean function f.

For example, how can I pick in {1, 1, 1, 3, 2, 4, 1, 4, 1, 1, 2, 1} the first element that does not equal 1?

A minimized version of an aswer (short code) is welcome.

$\endgroup$
4
$\begingroup$
list = {1, 1, 1, 3, 2, 4, 1, 4, 1, 1, 2, 1}

(* get position of first non-one *)
Position[list, _?(# != 1 &), 1, 1]

(* get positions of all non-one *)
Position[list, _?(# != 1 &)]

(* get value of first non-one *)
First@Cases[list, _?(# != 1 &)]

(*
{{4}}

{{4},{5},{6},{8},{11}}

3
*)

Many other ways (see, e.g. Pick, Except, Select for a start ... )

For your arbitrary function f, just use it in constructs like above, e.g.:

Position[list, _?f]
$\endgroup$
  • $\begingroup$ Hmm, I'm not familiar with _?, this seems really slick. So this is a way to turn a boolean expression into a pattern? Can't find _? in the Mathematica 6 manual... $\endgroup$ – Leo Jun 1 '14 at 21:22
  • $\begingroup$ @LeonLampret: As I said, there are many ways to do this kind of thing, I'm sure you'll see others in answers. See here for the pattern test (?) info. You might also look at condition, another way this kind of thing can be done. $\endgroup$ – ciao Jun 1 '14 at 21:26
  • 2
    $\begingroup$ @Leon Lampret - maybe a little bit easier to read for us starters: First@Position[list, a_ /; a != 1] $\endgroup$ – eldo Jun 1 '14 at 21:38
  • $\begingroup$ @eldo: Why doesn't your or rasher's code work: n=3; l={{2,1,3},{1,3,2}}; Position[l, _?(#[[n]]!=n&), 1, 1] First@Position[l, a_ /; a[[n]]!=n] It should return $2$. $\endgroup$ – Leo Jun 18 '14 at 2:23
  • $\begingroup$ @LeonLampret: Do this Position[l, _?((Sow[#]; #[[n]] != n) &), 1, 1] // Reap ... observe the result. Now, try this Position[l, _?(#[[n]] != n &), 1, 1, Heads -> False] for your sublist case. Reply back if not clear why this is... $\endgroup$ – ciao Jun 18 '14 at 5:04
3
$\begingroup$
list = {1, 1, 1, 3, 2, 4, 1, 4, 1, 1, 2, 1};

Some alternatives to Position:

f = (# != 1 &) (* say *)
Pick[Range[Length@list], f /@ list]
(* {4,5,6,8,11} *)

Select[Range[Length@list], f@list[[#]] &]
(* {4,5,6,8,11} *)

Select[Range[Length@list], f@list[[#]] &, 1]
(* {4} *)

Join@@ MapIndexed[If[f@#, #2, ## &[]] &, list]  (* credit for ##&[]: Mr.W and ?? *)
(* {4,5,6,8,11} *)

Catch@MapIndexed[If[f@#, Throw[#2]] &, list]
(* {4} *)
$\endgroup$

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.