I am working through the course Programming Paradigms via Mathematica. One of the exercises asks that you construct a function that mimics Select,even with three arguments. It also includes the following direction:
Do not use the
Select[]function in your definition.
Here is an example of how Select works:
Select[{1, 2, 3, 4, 6, 8, 10}, EvenQ, 4]
(* {2, 4, 6, 8} *)
First I tested the following code and got the same result as Select:
l1 = {1, 2, 3, 4, 6, 8, 10};
l2 = {};
crit = EvenQ;
n = 4;
While[Length[l1] > 0 && Length[l2] < n,
If[crit[First[l1]], l2 = Append[l2, First[l1]]];
l1 = Rest[l1];
]
l2
(* {2, 4, 6, 8} *)
I then tried to write a function that would do the same thing (caution causes infinite loop):
Clear[whileSelect]
whileSelect[l1_List, crit_, n_] := Module[{l2},
While[Length[l1] > 0 && Length[l2] < n,
If[crit[First[l1]], l2 = Append[l2, First[l1]]];
l1 = Rest[l1];
]
l2
]
However I got a series of Set::shape: Lists {1,2,3,4,6,8,10} and {2,3,4,6,8,10} are not the same shape. >> error messages and the code put the computer into an infinite loop. I have looked at documentation on Module,Rest,Set and If but have not been able to figure out what I am doing wrong. I would greatly appreciate a point in the right direction.
l1in a temporary variable. TrywhileSelect[l1_List, crit_, n_] := Module[{l1temp = l1, l2}, (* stuff *)].l1 = Rest[l1]will not work because if, say, you executedwhileSelect[{1, 2, 3, 4, 6, 8, 10}, EvenQ, 3], you then encounter absurdities like{1, 2, 3, 4, 6, 8, 10} = Rest[{1, 2, 3, 4, 6, 8, 10}]due to replacement. But I'll let someone else flesh out the details... – J. M.'s missing motivation Jun 21 '13 at 14:01Module[{l2}...toModule[{l1temp = l1, l2}...I also changed all the instances ofl1inside the definition tol1temp, however I just get error messages and(*Null Hold[Append[l2$29158, 2], 2, 2, 2,...*)– Clif Jun 21 '13 at 14:17whileSelect[l1_List, crit_, n_Integer] := Module[{l1temp = l1, l2 = {}, temp}, While[Length[l1temp] > 0 && Length[l2] < n, temp = First[l1temp]; If[crit[temp], AppendTo[l2, temp]]; l1temp = Rest[l1temp]]; l2], and note well what I did differently. – J. M.'s missing motivation Jun 21 '13 at 14:35Traceto see if I can understand howl1temp=Rest[l1temp]worked, whereasl1=Rest[l1]didn't, it may take a while. – Clif Jun 21 '13 at 14:53Take[Pick[list, fQ /@ list, True], max]– amr Jun 21 '13 at 23:29fQ) is applied to everylistelement; a second problem occurs ifmaxexceeds the number of matches. Also, there is no need forTrueinPickas that is the default. If one chooses not to use built-in functions with a length parameter (e.g.Cases) I would use something like:select[lst_List, crit_, n_: Infinity] := Module[{f, r = 0}, f = If[r < n, If[crit@#, r++; Sow @ #], Return[]] &; Reap[f ~Scan~ lst][[2, 1]] ]with a block-based optimization if appropriate. – Mr.Wizard Jun 22 '13 at 20:42Reaplike this:{{_, {}} -> {}, {_, {out_}} :> out}to handle the case where the length is 0. then again, that could just be checked in the beginning. derp derp. – amr Jun 22 '13 at 21:27