Enter Your Email Address to Watch This Lesson

Your link to unlock this lesson will be sent to this email address.

Unlock this lesson and all 833 of the free egghead.io lessons, plus get JavaScript content delivered directly to your inbox!



Existing egghead members will not see this. Sign in.

Just one more step!

Check your inbox for an email from us and click link to unlock your lesson.



Declaratively Map Predicates to Object Properties Using Ramda where

2:34 JavaScript lesson by

Sometimes you need to filter an array of objects or perform other conditional logic based on a combination of factors. Ramda's where function gives you a concise way to declaratively map individual predicates to object properties, that when combined, cover the various facets of your conditions. In this lesson, we'll look at how this powerful function can be used for scenarios requiring a complex predicate function.

Get the Code Now
click to level up

egghead.io comment guidelines

Avatar
egghead.io

Sometimes you need to filter an array of objects or perform other conditional logic based on a combination of factors. Ramda's where function gives you a concise way to declaratively map individual predicates to object properties, that when combined, cover the various facets of your conditions. In this lesson, we'll look at how this powerful function can be used for scenarios requiring a complex predicate function.

Avatar
Hozefa

Whats the advantage of using Ramda over lodash? They look to doing very similar things.

In reply to egghead.io
Avatar
Andrew Van Slaars

I'll start by saying that lodash is an awesome library, I have nothing against it. That being said, the biggest advantage Ramda has over lodash is the combination of argument order and automatic function currying. So, for something like filter, lodash takes the collection as the first argument, where ramda takes the predicate function first, and it then curries that function. So, R.filter(x => x % 2 == 0) returns a new function that you just have to pass data to. To accomplish the same thing with lodash, it would look like this: _.partial(_.filter, _, (x) => x%2==0) where you need to use partial application to return a partially applied version of filter function and a placeholder to account for the fact that I don't have the data yet and it is expected as the first argument to filter.

Having curried functions that can be used on different data contributes to building small, reusable functions and it also makes it easier to put together functional pipelines or compositions while keeping the code readable.

You can accomplish the same things with the functional programming variant of lodash, lodash/fp. Using lodash/fp gets you most of the same capabilities, but it doesn't offer lenses, and lenses can be very powerful.

Hope this helps.

In reply to Hozefa

Here I've included Ramda and I have a list of product objects. I also have a predicate defined that simply returns true for every item and I'm piping my product data through a filter and a call to pluck that's going to grab the name off of each product that makes it through the filter. I assign that to results and I log it in.

If I run this in its current state, I'll get back the names of every product in my product array. Let's say I just want to return items there in the clothes category. I jump back into the code and I can just replace my predicate with a function that takes in a product and checks the product category against the value "clothes."

If I run this again, I'll get back just the jeans, hoodie, and sneakers. Let's say I want to filter this further and I only want clothes where the stock level is under 50. I can do that by just updating this and I can say prod.doc less than 50. I can run that again and I'll get back just the hoodie and the sneakers.

What if I also had to filter on price? I could add a third condition to this predicate, but this is going to get messy and out of hand really fast. That's going to make it more error-prone, harder to read, and harder to follow.

This is where Ramda's where function comes in. I'm going to take this entire predicate function and get rid of it. I'm going to replace it with a call to r.where and where is going to take an object as its first argument. This object is going to map keys from our target object to predicate functions that are going to check that property individually.

Let's start with category. I want to filter for the clothes category so I'm going to use r.equals and just check that v equals clothes. I want to filter based on stock so I'll add a stock property. I want the items where the stock is under 50 so I'm going to use r.lessthan.

The arguments for lessthan come in in a slightly different order than we're used to. I'm going to put a placeholder because I want my incoming data for my property value to go here. My second argument is going to be the value that I'm checking against.

If I save this and I run it, you'll see that I get back hoodie and sneakers, just like I did before. But now my predicate is way more declarative. Adding a third check becomes trivial and let's say I just want to check against price, but this time I want to check for price where it's less than 100. I run that and I only get back the hoodie.

HEY, QUICK QUESTION!
Joel's Head
Why are we asking?