Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I am interested in mapping a function, f over a (long) list which contains duplicates. Since this function takes a while to evaluate I would like to make use of this duplication to speed up the mapping.

Attempt

Let us say my list is

list = {a, a, b, a, c, b}

my purpose is to map f over list efficiently. I have defined a function

MapDuplicate[f_, list_] := Module[{ff, list1, ulist},
list1 = ff /@ list; (* ff is dummy f *) 
ulist = Union[list]; (* the reduced list *)
rr = Dispatch[Thread[(ff /@ ulist) -> (f /@ ulist)]];
list1 /. rr]

which does the trick,

MapDuplicate[f1, list]

(* {f1(a),f1(a),f1(b),f1(a),f1(c),f1(b)} *)

but I strongly suspect there is a more elegant (using Ordering? SparseArray?) of doing this.

Question

Any idea on how to do this more efficiently (e.g. without duplicating the list) My apologies in advance if the answer turns out to be trivial.

share|improve this question
2  
Considered memoization? I.e., f[x_]:=f[x]= your definition used with Map: f/@list –  kguler Aug 19 '12 at 13:03
    
No I had not! I tend to think of memorization as attached to the function rather than to lists. I guess it would do the trick. –  chris Aug 19 '12 at 13:04
    
Though if I want to parallelize the mapping I suspect it won't work cf mathematica.stackexchange.com/questions/9186/… –  chris Aug 19 '12 at 13:07
2  
Keep in mind that both memoization or other hash-based approaches (rules, Dispatch, etc) may actually make things slower for numerical lists when your function is compilable, since Map auto-compiles and switching to memoization etc you will lose that advantage (not to detract from the suggestions to use memoization etc, since those are the right things to do generically). –  Leonid Shifrin Aug 19 '12 at 19:52
add comment

1 Answer 1

up vote 14 down vote accepted
dispatchTable = Dispatch[ # -> g[#] & /@ DeleteDuplicates[list]]
(* {a -> g[a], b -> g[b], c -> g[c]}  *)
list/.dispatchTable
(* {g[a], g[a], g[b], g[a], g[c], g[b]} *)

or memoization:

f[x_]:=f[x]= 3 x (* say *)

with Map

f/@list
(*  {3 a, 3 a, 3 b, 3 a, 3 c, 3 b} *)

or with ParallelMap:

ParallelMap[f, list]  
share|improve this answer
    
it seems to me the last option, ParallelMap will not be as efficient as it should be because sub-kernels will not know about what other kernels have already memorized. –  chris Aug 19 '12 at 13:16
    
@chris, good point. I have not done any testing with ParallelMap; and just saw your related question. Parallelization versus memoization (in case the choice is one of either/or) would make a great question: pros/cons, trade-offs involved etc. –  kguler Aug 19 '12 at 13:23
1  
I suggest modifying your answer to dispatchTable =Dispatch[ # -> g[#] & /@ DeleteDuplicates[list]] which will makes it more efficient if the dispatch table is long –  chris Aug 19 '12 at 13:23
    
@chris, another great point. I actually did mean to use Dispatch:) –  kguler Aug 19 '12 at 13:25
    
first option (dispatch) seems about 30 % faster. –  chris Aug 19 '12 at 13:35
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.