DEV Community

Cover image for Dealing with collections in functional way.
artydev
artydev

Posted on

Dealing with collections in functional way.

If there is a domain where functional programming (FP) shines, it's when dealing with lists, collections, arrays of objects.
Lisp is certainly the best prove of it.

Let's see how FP can help us with a simple example.

Suppose we have the following object :

let pets = [
  {
    petname : "Bill",
    breed : "poodle",
    weight: 12,
    owner : {
      ownername : "Paul",
      contribution : {
        amount : 32,
        payed : false
      },
      address : {
        city :  "Paris"
      }
    }
  },
  {
    petname : "Maya",
    race : "pointer",
    weight: 27,
    owner : {
      ownername : "Henri",
      contribution :  {
        amount : 12,
        payed : true
      },
      address : {
         city :  "London"
      }
    }
  },
  {
    petname : "Ooper",
    race : "setter",
    weight: 20,
    owner : {
      ownername : "Nicolas",
      contribution :  {
        amount : 12,
        payed : true
      },
      address : {
         city :  "London"
      }
    }
  }
]
Enter fullscreen mode Exit fullscreen mode

The goal is to retieve, the owner's name and corresponding pet names where the property payed is true;

To accomplish our goal we will need a few helpers in our toolbox :


const pickprop = (prop) => (obj) => !!obj[prop] ? obj[prop] : false;

const map = (f) => (arr) => arr.map(f);

const filter = (f) => (arr) => arr.filter(f);

const pipe = (...fns) => initial =>  { return fns.reduce((acc, f) => f(acc), initial) };

Enter fullscreen mode Exit fullscreen mode

The only tricky function is the pipe function.

pipe takes a list of functions, and iteratively 'feed' every function with the result of the previous function call.
The computation starts when the initial value is passed.

With those tools at our disposal, let's declare some constants, which are in fact functions.

const tap = (p) => {console.log(p); return p;}

const owner = pickprop("owner");
const petname =  pickprop("petname")
const contribution = pickprop("contribution");
const payed = pickprop("payed");

const ownerpayed =  pipe(owner, contribution, payed)
const ownername = pipe(owner, pickprop("ownername"))

Enter fullscreen mode Exit fullscreen mode

Notice how we can access fluently the properties of the object without relying in ugly 'dot' notation.

Here is the 'business part' :-)


const filterpayed = filter(ownerpayed);

Enter fullscreen mode Exit fullscreen mode

Here the presentation part :


const ownerandpet = map(p => ({owner: ownername(p), petname : petname(p)}));

Enter fullscreen mode Exit fullscreen mode

Here the main part :


let main = pipe ( 
    filterpayed 
  , ownerandpet
);

Enter fullscreen mode Exit fullscreen mode

Finaly we can execute our main function :


console.log (main(pets))

Enter fullscreen mode Exit fullscreen mode

The final result is :


[ { owner: 'Henri', petname: 'Maya' }, { owner: 'Nicolas', petname: 'Ooper' } ]

Enter fullscreen mode Exit fullscreen mode

A step further :


const filterownerpayed = filter(p => ownerpayed(p) == true);
const filterstayinlondon = filter(p => ownercity(p) == "London")
const ownerandpet = map(p => ({owner: ownername(p), petname : petname(p)}));

let main = pipe ( 
    filterownerpayed 
  , filterstayinlondon
  , tap
  , ownerandpet
);

Enter fullscreen mode Exit fullscreen mode

The beauty of this, is that all our filters functions are testable, and you can put any 'middleware' in the main function.

You can for example insert the tap function anywhere in the chain.

You can of course stick with the traditional way :


let main = function (pets) {
  return pets
    .filter(p => p.owner.contribution.payed)
    .filter(p => p.owner.address.city == "London")
    .map(p => ({owner: p.owner.ownername, petname : p.petname}) )
}

Enter fullscreen mode Exit fullscreen mode

Hope you enjoyed.

You can play with the demo

Top comments (0)