Map Filter Reduce

Map-reduce is a silver bullet strategy created for processing data.

As a lover of functional programming I like to use map, filter, and reduce for data processing.

Let's imagine that we have got a list of students.

This example is using seeded random!

var students = [];
var rand = Math.random.seeded.rand;

rand.setSeed('students example');

for(var i = 0; i < 1000; i++) 
  students.push({
    name: 'Some name',
    sex: rand(['male', 'female']),
    grade: rand(1, 11),
    letter: rand(['A', 'B', 'C', 'D']),
    weight: rand(20, 55),
    favorite: rand([
            'Math', 'Physics', 
      'Grammar', 'Literature', 
      'Informatics', 'Chemistry'
    ])
  });

// set students age
students.forEach(student => student.age = student.grade + 7 + (rand(-1, 1)|0));

Filter

… and we want to count the amount of females in the 9B class …

var count = students
  .filter( student => student.sex === 'female')
  .filter( student => student.grade === 9)
  .filter( student => student.letter === 'B')
  .length // 15

Reduce

… and, we want to know their average age …

var matched = students
  .filter( student => student.sex === 'female')
  .filter( student => student.grade === 9)
  .filter( student => student.letter === 'B');

var averageAge = matched
  .reduce( (accumulator, student) => accumulator += student.age, 0 )
  / matched.length;

Map

Map is a one-to-one mapping where each element of an array is processed through a function. The result is formed from the outputs of the function.

The classical demonstration of map is multiplying an array

[0,1,2,3,4,5].map( x => x*2 ) // [0,2,4,6,8,10]

But I want to show a more usable example. We have ten points, and we want to highlight the closest one.

var background = 0x113333 var points = []; for(var i = 0; i < 20; i++) points.push(new Point(rand(w), rand(h))); update = function(dt, t){ rect(0,0,w,h, background) for(var i = 0; i < 20; i++) { var point = points[i]; circle( point.x, point.y, 1, 0x00ffff ); } // Spice each point with distance to the mouse and then just sort them var closestPoints = points .map(point => ({point, distance: point.distance(mouse)})) .sort((p1, p2) => p1.distance - p2.distance) .map(({point}) => point); var closestPoint = closestPoints[0]; var currentStepColor = color( sin(t)*127+128, sin(t*1.4+21)*127+128, sin(t*2.4+5)*127+128 ); /*for(var i = 0; i < 4; i++) arrow(mouse, closestPoints[i], lighter(background, 1+i*0.2));*/ arrow(mouse, closestPoint, currentStepColor); circle( closestPoint.x, closestPoint.y, 3+sin(t*3), 0x77ff00 ); } move = function(){}