Sorry, I thought you were combining two approaches rather than presenting an alternative, and misread your proposal as allocating a whole new array on each iteration (mixing map and concatenation).
map is just fine, it's growth-by-concatenation that's the bad idea (as your timing test shows). --Tim On Friday, October 17, 2014 12:23:59 PM Tamas Papp wrote: > What does "better" mean in this context, style or speed? For me map is > better style (but that is of course subjective), but it also appears to > be in the range of push! with respect to speed within measurement noise > and allocates less (unless I am using push! incorrectly): > > function give_funs1(n) > funs = [] > for i in 1:n > funs = [funs, () -> i] > end > funs > end > > function give_funs2(n) > map((i) -> (() -> i), 1:n) > end > > function give_funs3(n) > result = Any[] > for i in 1:n > push!(result, () -> i) > end > result > end > > @time give_funs1(100000); > @time give_funs2(100000); > @time give_funs3(100000); > > julia> @time give_funs1(100000); > elapsed time: 31.811824021 seconds (40187982672 bytes allocated, 69.98% gc > time) > > julia> @time give_funs2(100000); > elapsed time: 0.018686499 seconds (7992040 bytes allocated) > > julia> @time give_funs3(100000); > elapsed time: 0.030754734 seconds (10890064 bytes allocated, 82.97% gc time) > > Note that gc of course is idiosyncratic in this case and dominates the > measurement, and can occur for both 2 and 3. > > Best, > > Tamas > > On Fri, Oct 17 2014, Tim Holy wrote: > > As for the accumulation, far better than either is to use push!. > > > > --Tim > > > > On Friday, October 17, 2014 09:48:49 AM Tamas Papp wrote: > >> I am not sure if I understood the question, but if the purpose is to > >> store the function you created before accumulating it in a list, you > >> could use > >> > >> function give_funs() > >> > >> funs = [] > >> for i in 1:5 > >> > >> newfun = () -> i > >> funs = [funs, newfun] > >> > >> end > >> funs > >> > >> end > >> > >> Also, accumulating the vector by concatenation may not be idiomatic in > >> this case. A more compact way would be > >> > >> function give_funs() > >> > >> map((i) -> (() -> i), 1:5) > >> > >> end > >> > >> Best, > >> > >> Tamas > >> > >> On Thu, Oct 16 2014, Evan Pu <[email protected]> wrote: > >> > Consider this code: > >> > > >> > function give_funs() > >> > > >> > funs = [] > >> > for i in 1:5 > >> > > >> > function newfun() > >> > > >> > i > >> > > >> > end > >> > funs = [funs, newfun] > >> > > >> > end > >> > funs > >> > > >> > end > >> > > >> > The intention is to create 5 functions and store them in a list called > >> > "funs". > >> > All the functions take no argument, and when the ith function is > >> > called, > >> > it > >> > returns i. > >> > > >> > However, when run... > >> > funs1 = give_funs() > >> > funs1[1]() # this should give 1, but instead it gives 5 > >> > funs1[2]() # this should give 2, but instead it gives 5 as well > >> > > >> > This is problem goes away if I stop naming the function as "newfun" but > >> > instead use ananymous functions like so: > >> > funs = [funs, () -> i] > >> > however in real code I would like to give it a name so to be more clear > >> > what the function is suppose to compute > >> > > >> > It seems that these functions are bound by their function names, and > >> > since > >> > they're all named "newfun", the compiler over-write the old ones > >> > defined > >> > earlier. > >> > > >> > How should this be resolved?
