3
$\begingroup$

I have a list:

{a,b,c,d,e,f}

And a function sizeFunc[element_] which returns the size {rows,columns} of the element, for example:

In= sizeFunc[c]
Out= {3,3}

To be clear, all elements are symbolic. I want to find the first element in the above list whose size is not {1,1}. So far I tried:

Position[{a,b,c,d,e,f},(sizeFunc[#]=={1,1})&]

The above is just an attempt, I have no idea how to solve this problem. Thanks a lot for helping.

With for loop (what I want to avoid):

list={a,b,c,d,e,f};
For[k = 1, k <= Length[list], k++,
 If[sizeFunc[list[[k]]] != {1, 1},
  firstNonScalark = k; Break[];
 ]
];
$\endgroup$
  • $\begingroup$ =!= might be useful. $\endgroup$ – J. M. will be back soon Jul 27 '15 at 20:48
  • $\begingroup$ Do you mean Dimensions[ ]? $\endgroup$ – Dr. belisarius Jul 27 '15 at 20:48
  • $\begingroup$ @belisarius What do you mean? Dimensions[] has nothing to do with it, I have my own function sizeFunc[] and I'm searching for the first element from the left whose size is not {1,1} $\endgroup$ – space_voyager Jul 27 '15 at 20:51
  • 1
    $\begingroup$ LengthWhile[list, sizeFunc[#] == {1,1}&]+1. I think For is pretty awful in Mathematica and can always be avoided. If you do need a procedural loop, use Do which at least localizes the iterator, and is more compact and more readable. $\endgroup$ – Szabolcs Jul 27 '15 at 20:51
  • $\begingroup$ @Szabolcs Thanks it works BUT when no element in a list has size other than {1,1}, the returned value exceeds list dimensions by 1. How do I bound the value to the length of the list? $\endgroup$ – space_voyager Jul 27 '15 at 21:01
2
$\begingroup$

I'll define a sizeFunc to play with:

Clear[sizeFunc]
sizeFunc[a] = {1, 1}; sizeFunc[b] = {1, 1}; sizeFunc[c] = {3, 2}; 
sizeFunc[d] = {2, 4}; sizeFunc[e] = {1, 1}; sizeFunc[f] = {1, 1};

UPDATE:

OP mentioned the desired behavior when all elements return {1, 1}. Taking that into consideration, one can define the following function:

firstnonscalar[l_List] := Module[
  {position},
  If[(position = First@FirstPosition[l, el_ /; sizeFunc[el] != {1, 1}]) != "NotFound",
   position,
   Length[l]
  ]
 ]

As requested, this will return the position of the first element whose sizeFunc does not return {1, 1}, or alternatively the Length of the list, which is the position of the last element.


Original answer:

In my understanding of your question, you want the (position of) the first element whose sizeFunc is not {1,1}.

If you want the element itself, then the following would work:

SelectFirst[{a, b, c, d, e}, sizeFunc[#] != {1, 1} &]
(* Out: c *)

If you want the position of that element in the list, then the following would work instead:

First@FirstPosition[{a, b, c, d, e}, el_ /; sizeFunc[el] != {1, 1}]
(* Out: 3 *)

Here is what happens to these functions if there are no elements for which sizeFunc is different from {1, 1}:

Clear[sizeFunc]
sizeFunc[a] = {1, 1}; sizeFunc[b] = {1, 1}; sizeFunc[c] = {1, 1}; 
sizeFunc[d] = {1, 1}; sizeFunc[e] = {1, 1}; sizeFunc[f] = {1, 1};
SelectFirst[{a, b, c, d, e}, sizeFunc[#] != {1, 1} &]
First@FirstPosition[{a, b, c, d, e}, el_ /; sizeFunc[el] != {1, 1}]

(* Out:
Missing["NotFound"]
"NotFound"
*)

You didn't specify what to do in that case, so I'll leave the handling of those cases to whatever is best to your application.

$\endgroup$
  • $\begingroup$ Thanks a lot. If you want to modify your answer, the handling should be to output the position of the last element of the list. $\endgroup$ – space_voyager Jul 27 '15 at 21:27
  • $\begingroup$ Upvote for FirstPosition. I always feel silly putting those two 1s in arguments to Position and wonder why levelspec isn't the last argument. $\endgroup$ – Ian Jul 27 '15 at 21:30
  • $\begingroup$ @space_voyager OK thanks for the clarification; I included that in an ad hoc function. $\endgroup$ – MarcoB Jul 27 '15 at 21:41
  • $\begingroup$ @Ian Thank you. To be honest, I find the syntax and output of Position rather confusing myself, so I often have to look up to get just right. $\endgroup$ – MarcoB Jul 27 '15 at 21:42
  • $\begingroup$ @MarcoB thanks a lot! $\endgroup$ – space_voyager Jul 27 '15 at 22:00
2
$\begingroup$

If your size function behaves something like this:

sizeFunc[x_] := {1, 1}
sizeFunc[d] := {3, 2, 1}

then Select can get you the first element matching your negative criterion. Like this:

Select[{a, b, c, d, e, f}, sizeFunc[#]!={1, 1} &, 1]

If you want to use Position to get the position of the element in the list (rather than the element itself), you have to supply a pattern rather than a criterion.

Position[{a, b, c, d, e, f}, x_ /; sizeFunc[x] != {1, 1}, 1, 1]
$\endgroup$
  • $\begingroup$ Position[{a, b, c, d, e, f}, x_ /; sizeFunc[x] != {1, 1}, 1]]+1 did the trick! Thank you. $\endgroup$ – space_voyager Jul 27 '15 at 21:26
2
$\begingroup$

FirstPosition allows for a default value:

sizeFunc[a | b | d | e | f] = {1, 1};
sizeFunc[c] = {2, 3};

list = {a, b, c, d, e, f};

FirstPosition[list, _?(sizeFunc[#] != {1, 1} &), {Length @ list}]
{3}
sizeFunc[c] = {1, 1};

FirstPosition[list, _?(sizeFunc[#] != {1, 1} &), {Length @ list}]
{6}

Without FirstPosition one might use:

Position[list, _?(sizeFunc[#] != {1, 1} &), 1, 1] /.
  {{p_List} :> p, {} :> {Length@list}}
$\endgroup$
  • $\begingroup$ I didn't know that! Thank you for pointing that out. That makes for a nice terse one-liner. (+1) $\endgroup$ – MarcoB Jul 28 '15 at 4:42
  • $\begingroup$ @MarcoB Thanks for the link correction! I also added a method using Position that is reasonably clean. $\endgroup$ – Mr.Wizard Jul 28 '15 at 15:33

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.