🕷 zenspider.com

by ryan davis

Looking for the Ruby Quickref?

5 Minutes (per commit)

Published 2011-11-05 @ 18:52

Tagged thoughts

I’m learning Mathematica. Mostly for fun, but also because it is something totally new to me and it is an incredibly powerful system that has amazing capabilities to compute and visualize in ways not possible in Ruby. I’m spending time every day working through a couple old books on it and am finally hitting the meat that I wanted to really get into. But the real point is that I’m still learning, and therefore I suck at it.

One of the exercises is on pattern matching and function writing and it asked me to define the geometric mean. I got it working but I knew it wasn’t really up-to-par:

geometricMean[x__] := Block[{
   len = Length[{x}],
   terms = Map[Power[#, 1/len] &, {x}]
   }, Product[terms[[i]], {i, len}]]
geometricMean[{x__}] := geometricMean[x]

This defines geometricMean 2 different ways (one with multiple args, and one with a single list arg) and it does work both ways:

Out[137]= a^(1/5) b^(1/5) c^(1/5) d^(1/5) e^(1/5)
Out[138]= a^(1/5) b^(1/5) c^(1/5) d^(1/5) e^(1/5)

But I knew that the Block + Map + Product approach was probably kludgy. It turns out it was very kludgy. I didn’t need to do Product on the indexed elements of terms because I could Apply Times onto the result of the Map:

geometricMean[x__] := Apply[Times, Map[Power[#,1/Length[{x}]]&,{x}]]
geometricMean[{x__}] := geometricMean[x]

That’s actually a bit better. More readable at least. Next I dug a bit and realized that Power distributes across lists, making the entire Map unnecessary:

geometricMean[x__] := Apply[Times, Power[{x},1/Length[{x}]]]
geometricMean[{x__}] := geometricMean[x]

Refining a bit more, I can use the @@ shorthand for Apply:

geometricMean[x__] := Times @@ Power[{x},1/Length[{x}]]
geometricMean[{x__}] := geometricMean[x]

Next, I used the ^ shorthand for Power (it looks a bit uglier in plaintext, but formats exactly how you’d expect inside of Mathematica):

geometricMean[x__] := Times @@ ({x}^((1/Length[{x}])))
geometricMean[{x__}] := geometricMean[x]

At this point, I can be pretty happy with what I have. It works and it is succinct enough that you can tell at first glance what it does. But I wanted to get rid of those extra {x} lists I was making because I did my pattern matching the way I did. Inverting the evaluation order provides me with the cleanest solution I can come up with so far:

geometricMean[x_] := Times @@ (x^((1/Length[x])))
geometricMean[x__] := geometricMean[{x}]

Not bad! And it didn’t take me all that long to go from something that worked but was cumbersome to something that was fairly elegant and readable.

There are 1440 minutes in a day. That is 288 5 minute chunks. Plenty, right? There are many of those 5 minute chunks you can spare each day, right? Think about how much time a day you spend on reddit.

So spend those 5 minutes before every commit and review your diffs. You know you got it working (that was the whole point), now spend those 5 measly minutes asking “is there a more succinct way I can say this?” and use that time to explore and learn the nuance of whatever you’re working on.

Every 5 minutes you spend refining is a chance to learn more about the system you’re using.

Every 5 minutes you spend refining speeds up tasks in your future by allowing yourself to jump straight to the more succinct solution.

Every 5 minutes you spend refining is 30 minutes you wont have to spend debugging later.