Chris Hansen
Chris Hansen

Reputation: 8685

Functional programming example

This is to understand functional programming.

It comes from the the article on smacking magazine: http://www.smashingmagazine.com/2014/07/dont-be-scared-of-functional-programming/

Hi I have the following data

var data = [
  { 
    name: "Jamestown",
    population: 2047,
    temperatures: [-34, 67, 101, 87]
  },
  {
    name: "Awesome Town",
    population: 3568,
    temperatures: [-3, 4, 9, 12]
  }
  {
    name: "Funky Town",
    population: 1000000,
    temperatures: [75, 75, 75, 75, 75]
  }
];

I need to get the average temperature and average population and store in a new array

 [
   [average temperature, average population]
 ]

The way I was thinking of solving this problem is using two for loops. Why is that a bad way to solve the problem? Why is functional programming the answer?

Upvotes: 0

Views: 155

Answers (2)

jungy
jungy

Reputation: 3097

The way I was thinking of solving this problem is using two for loops.

There is nothing wrong with imperative programming. Many people prefer to write code this way and to them it feels natural. However, why not leverage some of the benefits of functional programming.

Why is that a bad way to solve the problem?

As stated above, it isn't necessarily a bad way to solve the problem but, let's have a look at the example code they used:

var coords = [],
    totalTemperature = 0,
    averageTemperature = 0;

for (var i=0; i < data.length; i++) {
  totalTemperature = 0;

  for (var j=0; j < data[i].temperatures.length; j++) {
    totalTemperature += data[i].temperatures[j];
  }

  averageTemperature = totalTemperature / data[i].temperatures.length;

  coords.push([averageTemperature, data[i].population]);
}

It solves the problem. Now here is the same snippet in a more functional way:

function average(sum, count) {
  return sum / count;
}

function sum(x, y) {
  return x + y;
}

var coords = data.map(function(item) {
  return [
    average(item.temperatures.reduce(sum), item.temperatures.length),
    item.population
  ];
});

Obviously, as @Fabio has pointed out it can be taken much further but, I wanted to show you a simpler example using the same logic.

Which do you find easier to reason with, test, etc...?

Why is functional programming the answer?

Functional programming isn't some silver bullet for the JavaScript language but, the beauty of JavaScript is that we can leverage paradigms from other languages.

Upvotes: 2

Fabio Beltramini
Fabio Beltramini

Reputation: 2511

Here's one (among many ways of doing it). Of course, a more specialized reduce function like average reducer instead of sum would increase the readability of the code, I think this version is easier to "come up with on your own" on the first iteration, and could then be refined.

function sum(a,b){return a+b;}
function flatten(a,b){return a.concat(b);}

    console.log([
      data.map(function(datum){
          return datum.temperatures;
        }).reduce(flatten,[]).reduce(sum,0)
      /data.map(function(datum){
          return datum.temperatures;
        }).reduce(flatten,[]).length
      ,
      data.map(function(datum){
          return datum.population;
        }).reduce(sum,0)
      /data.length
])

Now here's a more readable, but slightly harder to write versionn:

function total(running,x){return {sum:running.sum+x, count:running.count+1};}
function average(o){return o.sum/o.count;}
function flatten(a,b){return a.concat(b);}
function property(name){return function(x){return x[name];}}
var startingTotal={sum:0,count:0};

[
 average(data.map(property("temperatures")).reduce(flatten).reduce(total,startingTotal)),
 average(data.map(property("population")).reduce(total,startingTotal))
]

Upvotes: 1

Related Questions