       Re: working with lists

• To: mathgroup at smc.vnet.net
• Subject: [mg113214] Re: working with lists
• From: Leonid Shifrin <lshifr at gmail.com>
• Date: Tue, 19 Oct 2010 05:54:48 -0400 (EDT)
• References: <201010180947.FAA00936@smc.vnet.net>

```Sam,

The following seems to solve your problem. You did not specify whether
subtractions must accumulate - I assumed this is so.

In:= Clear[f];
f[x_List] :=
Module[{subtr = 0},
Map[If[Mod[# - subtr, 3] == 0, 2 (# - subtr++), # - subtr] &, x]]

In:= tst = {1, 2, 3, 5, 7}

Out= {1, 2, 3, 5, 7}

In:= f[tst]

Out= {1, 2, 6, 4, 12}

Generally, this sort of problems are hard to immediately translate into
purely functional Mathematica code, since the next elements depend on the
previous ones, but non-locally - the entire list after certain element gets
modified. Here is another (procedural) implementation:

In:=
Clear[ff];
ff[x_List] :=
Module[{i = 1, xl = x},
For[i = 1, i <= Length[xl], i++,
If[Mod[xl[[i]], 3] == 0, xl[[i]] *= 2; xl[[i + 1 ;;]] -= 1]];
xl]

In:= ff[tst]

Out= {1, 2, 6, 4, 12}

It can be compiled for speed:

fff =
Compile[{{x, _Integer, 1}},
Module[{i = 1, xl = x},
For[i = 1, i <= Length[xl], i++,
If[Mod[xl[[i]], 3] == 0, xl[[i]] *= 2;
xl[[i + 1 ;; Length[xl]]] -= 1]];
xl]];

In:= fff[tst]

Out= {1, 2, 6, 4, 12}

The first version can be compiled as well:

ffff =
Compile[{{x, _Integer, 1}},
Module[{subtr = 0},
Map[If[Mod[# - subtr, 3] == 0, 2 (# - subtr++), # - subtr] &, x]]]

In:= ffff[tst]

Out= {1, 2, 6, 4, 12}

It is interesting to compare speed on larger lists:

In:= ltst = RandomInteger[{1, 10000}, 10000];

In:= (res1 = f[ltst]); // Timing

Out= {0.521, Null}

In:= (res2 = ff[ltst]); // Timing

Out= {1.752, Null}

In:= (res3 = fff[ltst]); // Timing

Out= {0.762, Null}

In:= (res4 = ffff[ltst]); // Timing

Out= {0.02, Null}

In:= res1 == res2 == res3 == res4

Out= True

This shows that in this particular case, Map with procedural code embedding
is both superior in uncompiled form and helped much more by using Compile.
You could change Map to For loop  with the same effect - what matters here
is that by using an accumulator variable we dramatically reduce the number
of operations, as compared to the version where entire list gets modified
each time. This shows once again,  that for problems like this, procedural
paradigm serves you better (a rare case in Mathematica).

Hope this helps.

Regards,
Leonid

On Mon, Oct 18, 2010 at 2:47 AM, Sam Takoy <sam.takoy at yahoo.com> wrote:

> Hi,
>
> I'm not very good at working with lists. May I ask for someone to work
> out an example which has several elements of what I need to do.
>
> What's the best way to write a function f[list] that goes through each
> element of the lest, doubles each element divisible by three and reduces
> each of the following elements by 1. That is
>
>
> f[{ 1 2 3 5 7}] is { 1 2 6 4 12 }
>