# Reverse DeleteDuplicates using Information from Tally

I have a list of values, e.g., {1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5}. I delete the duplicates with

DeleteDuplicates[{1, 1, 1 ,2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5}];


{1, 2, 3, 4, 5}

I want to perform some calculations on each value and at the end reverse the process of deleting.

From Tally I know, how often the elements appear:

Tally[{1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5}];


{{1, 3}, {2, 2}, {3, 2}, {4, 5}, {5, 1}}

Now, from the calculations I have the new list {12, 14, 15, 16, 17}. I want to reverse the process of DeleteDuplicates on this list. Means: {{12,3},{14,2},{15,2},{16,5},{17,1}} -> So, that I get:

{12, 12, 12, 14, 14, 15, 15, 16, 16, 16, 16, 17}.

I want to do that, because the calculations take very long and I want to calculate duplicates two times.

• Are you familiar with the concept of memoization in Mathematica? It would allow you to map a function over the original list but only perform the long calculation once for each unique value. Nov 6, 2015 at 20:42
• Are the starting list and the second list always sorted? Nov 7, 2015 at 0:01

tal = {{1, 3}, {2, 2}, {3, 2}, {4, 5}, {5, 1}};

lis = {12, 14, 15, 16, 17};

Flatten @ MapThread[Table[#1, {#2}] &, {lis, Last /@ tal}]


{12, 12, 12, 14, 14, 15, 15, 16, 16, 16, 16, 16, 17}

Or

Flatten[ConstantArray @@@ Transpose[{lis, Last /@ tal}]]


The following can be used also for unsorted lists:

SeedRandom[42];
l = RandomInteger[{3, 8}, 10]
l /. Thread[# -> expensive/@ #] &@Union@l

(* {6, 6, 5, 3, 7, 3, 7, 3, 7, 4} *)
(* {expensive[6], expensive[6], expensive[5], expensive[3], expensive[7],
expensive[3], expensive[7], expensive[3], expensive[7], expensive[4]} *)


mylist = {1, 1, 1, 2, 2, 3, 3, 4, 4, 4, 4, 4, 4, 5};


another way to translate your approach is for example:

q[x_] := (Print["Computing..."]; f[x]);

Join @@ KeyValueMap[ConstantArray, KeyMap[q, Counts[mylist]]]

Computing...
Computing...
Computing...
Computing...
Computing...
{f[1],f[1],f[1],f[2],f[2],f[3],f[3],f[4],f[4],f[4],f[4],f[4],f[4],f[5]}


unless you prefer use the excellent memoization approach proposed by @Simon Woods:

p[x_] := p[x] = (Print["Computing..."];f[x]);
p /@ mylist

Computing...
Computing...
Computing...
Computing...
Computing...
{f[1],f[1],f[1],f[2],f[2],f[3],f[3],f[4],f[4],f[4],f[4],f[4],f[4],f[5]}


In both cases, you can see that computation of f took place only 5 times and not as many times as the number of elements in the list.

tal = {{1, 3}, {2, 2}, {3, 2}, {4, 5}, {5, 1}};
lis = {12, 14, 15, 16, 17};
MapThread[Sequence @@ ConstantArray[#1, #2[[2]]] &, {lis, tal}]