4
$\begingroup$

I have a list which contains sublists, e.g.

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

I then map a function through each sublist. This function should replace each occurrence of a by (say) a number, starting from 1 and increasing up to the total number of occurrences of a, like so:

Map[f,list,{2}]
(*{{1,b}, {1,b,c}, {1,b,2,3}, {b,c}, ...}*)

I remember I once saw a very clever implementation of something similar using memoization, but I could be mistaken. How can I write a suitable function f that would do do the job?

$\endgroup$
7
$\begingroup$

Without memoization but works too :)

Block[{i}, (i = 1; # /. a :> i++)] & /@ {{a, b}, {a, b, c}, {a, b, a, a}, {b, c}}

And with:

ClearAll[f];
f[a, _Integer] = 0;
f[a, {p_, _}] := f[a, p] += 1;
f[x_, _] := x;

MapIndexed[f,
 {{a, b}, {a, b, c}, {a, b, a, a}, {b, c}},
 {2}
 ]
{{1, b}, {1, b, c}, {1, b, 2, 3}, {b, c}}
$\endgroup$
  • $\begingroup$ Damn, 40 secs :)- Add a scoping construct for i, please:) $\endgroup$ – Dr. belisarius Sep 15 '14 at 17:47
  • $\begingroup$ @Ziofil Please don't. It would be too soon :) $\endgroup$ – Kuba Sep 15 '14 at 17:51
  • $\begingroup$ By the way, I used Block on the function instead of including the list: Block[{i = 1}, # /. a :> i++] & /@list, so that my function f is well defined $\endgroup$ – Ziofil Sep 15 '14 at 17:53
  • 1
    $\begingroup$ +1. Localizing i is quite difficult in this context. Block is not sufficient -- try it with the list {{a, a, i, a}}. The usual cure, Module, won't work here either due to inner scope renaming. It will take some gymnastics to localize i properly: Module[{i}, Module @@@ (Hold[{i = 1}, # /. a :> i++] &)]. @belisarius $\endgroup$ – WReach Sep 16 '14 at 3:54
  • 1
    $\begingroup$ Another localization option is to avoid using a pure function, e.g. Module[{f, i = 1}, f[x_] := x /. a :> i++; f] /@ {{a, a, i, a}}. $\endgroup$ – WReach Sep 16 '14 at 4:14
6
$\begingroup$

Here is a crude way using FoldList.

 foo[lis_, var_] := Module[{i, f}, f[var] := ++i;
    f[x_List] := f /@ x;
    f[x_] := x;
    Rest @ FoldList[(i = 0; f[#2]) &, var, lis]
  ]

Use:

foo[list, a]
{{1, b}, {1, b, c}, {1, b, 2, 3}, {b, c}}
$\endgroup$
2
$\begingroup$

Here is the closurized way that the OP might have had in mind:

closfunc[l_]:= With[{foo = Module[{num}, num = 1; If[# == "a", num++, #] &]},
   Map[foo, l]]

Now Map[closfunc, listoflists] will do the right thing.

$\endgroup$

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.