my main question is how I can compare the last output of a nested function with all the previous ones and stop iterating when I find a repeating value. (I have 2 other questions but I think they are so simple that they do not deserve a separate topic, so I'll post them here).
For example, let's say I want to see if a number is happy or not (I got the idea from a recent topic) and look at all the iterations. Here is the code I wrote
f = NestWhileList[Total @ (#^2 & @ IntegerDigits[#]) &, #, !(# == 1 || # == 4) &] &
for f@309
I get
{309, 90, 81, 65, 61, 37, 58, 89, 145, 42, 20, 4}
I wrote that code because I know that the list will eventually reach 1 or 4. What if I didn't? Let's say I know only that the list will reach a cycle, but the numbers can change. How can I compare the last iteration with all the others and stop when I find a number repeated? In this case the list should stop at
{309, 90, 81, 65, 61, 37, 58, 89, 145, 42, 20, 4, 16, 37}
because 37 is already there.
Subquestion 1.
f @ {309,21}
don't work, I have to write f /@ {309,21}
. I thought that pure functions were listable, like #^3 &
, why is f not? Has it something to do with Nest?
Subquestion 2.
It's a little question about pure functions, what's the difference between f := #^2 &
and f = #^2 &
?
EDIT 2
Thank you for the answers, if someone is curious, here is a timing test on my computer. Naming
(* Leonid *)
f1[n_] := Module[{appeared}, appeared[_] = False;
NestWhileList[Total[IntegerDigits[#]^2] &,
n, (! appeared[#] && (appeared[#] = True)) &]];
(* Belisarius/WReach *)
f2 = NestWhileList[Total@(#^2 &@IntegerDigits[#]) &, #, Unequal,
All] &;
(* j.Vincent *)
f3 = NestWhile[Append[#, Total@(#^2 &@IntegerDigits[#[[-1]]])] &, {#},
Length[Union[#]] == Length[#] &] &;
f4 = Block[{continue}, (continue[a_] := (continue[a] = False; True);
NestWhileList[Total@(#^2 &@IntegerDigits[#]) &, #, continue])] &;
(* image_doctor *)
f5 = FixedPoint[
DeleteDuplicates@
Append[#, Total@(#^2 &@IntegerDigits[#]) & @ Last[#]] &, {#}] &;
(* WReach *)
nestUntilCycle[f_, x_] :=
Module[{fast = x, more = True},
NestWhile[f, f@x, (fast = f@f@fast; # != fast) &];
NestWhileList[(If[more, fast = f@fast]; f@#) &,
x, # != fast || more && (more = False; True) &]];
(* Mr.Wizard *)
f6 = Module[{in},
in[x_] := (in[x] = "Exit"; Total[IntegerDigits[x]^2]);
Most@NestWhileList[in, #, # =!= "Exit" &]] &;
f7 = NestWhileList[Total[IntegerDigits[#]^2] &, #,
Signature@{##} =!= 0 &, All] &;
I obtained
AbsoluteTiming[f1 /@ Range[1, 25000];]
AbsoluteTiming[f2 /@ Range[1, 25000];]
AbsoluteTiming[f3 /@ Range[1, 25000];]
AbsoluteTiming[f4 /@ Range[1, 25000];]
AbsoluteTiming[f5 /@ Range[1, 25000];]
AbsoluteTiming[nestUntilCycle[Total@(#^2 &@IntegerDigits[#]) &, #] & /@ Range[1,25000];]
AbsoluteTiming[f6 /@ Range[1, 25000];]
AbsoluteTiming[f7 /@ Range[1, 25000];]
{3.0888054, Null}
{1.7004030, Null}
{2.6676047, Null}
{2.5740045, Null}
{1.9500035, Null}
{5.6784099, Null}
{2.9640052, Null}
{2.6520046, Null}
Time was not an issue, I included it only for completeness. Note: as Leonid and others pointed out, in this case the differences are negligible, but with longer lists and cycles it is better to avoid methods with quadratic complexity.
Let's use the function proposed by Mr.Wizard and see what changes
f0 = Mod[# + 1, 2000] &;
(* Leonid *)
f1[n_] := Module[{appeared}, appeared[_] = False;
NestWhileList[f0, n, (! appeared[#] && (appeared[#] = True)) &]];
(* Belisarius/WReach *)
f2 = NestWhileList[f0, #, Unequal, All] &;
(* j.Vincent *)
f3 = NestWhile[Append[#, f0[#[[-1]]]] &, {#},
Length[Union[#]] == Length[#] &] &;
f4 = Block[{continue}, (continue[a_] := (continue[a] = False; True);
NestWhileList[f0, #, continue])] &;
(* image_doctor *)
f5 = FixedPoint[DeleteDuplicates@Append[#, f0 @ Last[#]] &, {#}] &;
(* WReach *)
nestUntilCycle[f_, x_] :=
Module[{fast = x, more = True},
NestWhile[f, f@x, (fast = f@f@fast; # != fast) &];
NestWhileList[(If[more, fast = f@fast]; f@#) &,
x, # != fast || more && (more = False; True) &]];
(* Mr.Wizard *)
f6 = Module[{in}, in[x_] := (in[x] = "Exit"; f0[x]);
Most@NestWhileList[in, #, # =!= "Exit" &]] &;
f7 = NestWhileList[f0, #, Signature@{##} =!= 0 &, All] &;
On my pc
AbsoluteTiming[f1@ 0;]
AbsoluteTiming[f2@ 0;]
AbsoluteTiming[f3@ 0;]
AbsoluteTiming[f4@ 0;]
AbsoluteTiming[f5@ 0;]
AbsoluteTiming[nestUntilCycle[f0, #] & @0;]
AbsoluteTiming[f6@ 0;]
AbsoluteTiming[f7@ 0;]
{0.0110007, Null}
{17.0559755, Null}
{0.0940053, Null}
{0.0080004, Null}
{0.0160010, Null}
{0.0150008, Null}
{0.0100006, Null}
{0.3420196, Null}
Calling out f2
and trying with f0 = Mod[# + 1, 20000] &
these are the results
{0.1140065, Null}
{8.9305108, Null}
{0.0840048, Null}
{0.9790560, Null}
{0.1470084, Null}
{0.1040060, Null}
{55.5261759, Null}
NestWhile(List)
, my solution there uses it. The problem with currently posted answers based onAppend
is thatAppend
-based accumulation method has a quadratic complexity in the size of the iteration results, and that sort or destroys the purpose ofNestWhile(List)
. $\endgroup$NestWhile
abstraction is just not very good, and using data structures optimal for a particular problem (lists, hashes, trees, etc) may be better. $\endgroup$