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 want to map a function over a matrix of rank n, for example:

PercentChange[v_?VectorQ] := Differences@v/Most@v*100
PercentChange[v_] := Map[PercentChange, v, {Length@Dimensions@v-1}]

m = N@Range@10;

PercentChange /@ {m, {m, m}, {{m, m}, {m, m}}}

This works as expected.

Now, as a lazy beginner, I thought that I could get rid of the duplicate definition of "PercentChange" and simply state:

PercentChange[v_] := Map[PercentChange, v, {Length@Dimensions@v - 1}]

However, to my disappointment this didn' t function because "Map" doesn't accept a level {0} parameter:

Map[Differences@m/Most@m, m, {0}]*100

On the other hand, this functions in all cases:

Percent2[v_] := Map[Differences@#/Most@# &, v, {Length@Dimensions@v-1}]*100

How would you write this without duplication and slot-notation?

share|improve this question

1 Answer 1

up vote 3 down vote accepted

Your assertion that Map does not accept a levelspec of {0} is incorrect:

Map[f, bar[1, 2, 3], {0}]
f[bar[1, 2, 3]]

For your second definition:

Percent2[v_] := Map[Differences@#/Most@# &, v, {Length@Dimensions@v-1}]*100

Which duplication are you referring to, and why don't you like Slot notation?

Anyway, if you are merely looking for a different style perhaps:

fn[v_?VectorQ] := Differences@v / Most@v * 100
fn[a_?ArrayQ]  := fn /@ a

fn[{a, b, c}]
fn[{{a, b, c}, {q, r, s}}]
{(100 (-a + b))/a, (100 (-b + c))/b}

{{(100 (-a + b))/a, (100 (-b + c))/b}, {(100 (-q + r))/q, (100 (-r + s))/r}}

Also ArrayDepth[v] - {1} is a little cleaner than {Length @ Dimensions @ v - 1}.

Although far less clean in my opinion, we could also take advantage of the second parameter of Differences, and use a substitute for Most, to perform this operation without an explicit Map.

fn2[a_?ArrayQ] :=
 With[{depth = PadLeft[{1}, ArrayDepth[a]]},
   Differences[a, depth] / Part[a, ##] * 100 & @@ (depth /. {0 -> All, 1 -> ;; -2})
 ]

Test:

m = N @ Range @ 10;
lists = {m, {m, m}, {{m, m}, {m, m}}};
fn /@ lists === fn2 /@ lists
True
share|improve this answer
    
(1) Just try "Map[Differences@m/Most@m*100, m, {0}]" with the above definition of "m" - it doesn't function. (2) With "duplication" I meant the initial definition of "PercentChange" (lines 1 and 2 of my question). –  eldo May 16 at 21:01
    
@eldo The problem with Map[Differences@m/Most@m*100, m, {0}] is that the first argument is not a function. –  Mr.Wizard May 16 at 21:05
    
Thanks for clarifying this to me ;) –  eldo May 16 at 22:04
    
@eldo The "wink" suggests to me that you say that sarcastically; if that is the case I genuinely don't know what you're looking for and I am trying to be helpful. If however I misunderstand you are welcome. Either way I will attempt to answer more questions if I am able to understand what you are asking. –  Mr.Wizard May 17 at 2:50
    
The "wink" was a polite smile –  eldo May 17 at 7:10

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.