Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional approach of removing items in a list based on nested property values

I am trying move more towards functional programming in my javascript applications. I currently use the library ramda as a base lib for this.

My desire:

  1. Create a function removeUserFromList(username, list) which returns the items in the list that does not match the username.
  2. Make the implementation as short as possible, relying on existing functions in the Ramda library as much as possible.

Conditions:

A list containing nested user objects:

[{
    providers: {
        github: {
            login: "username1"
        }
    }

},
{
    providers: {
        github: {
            login: "username2"
        }
    }

}]    

Acheived so far:

var list = [{providers: {github: {login: "username1"}}},
            {providers: {github: {login: "username2"}}}];

var getLoginName = R.useWith(R.path('providers.github.login'));
var isLoginNameEq = R.useWith(R.eq, getLoginName);

isLoginNameEq(list[0], "username1") // => true

//From this point on I am totally clueless, 
//but I believe I should combine these functions 
//with R.reject in some way.

Plunkr demo:

http://plnkr.co/edit/1b5FjxV3Tcgz7kozW1jX

Question:

Is there any better suited function to achieve something similar to R.eq but on nested objects (perhaps R.pathEq)?

like image 922
horte Avatar asked Oct 08 '14 10:10

horte


3 Answers

I just got a pull request for R.pathEq merged. It won't be usable until the next release of ramda.js (current version is 0.6.0) but meanwhile you can recreate it like this:

var pathEq = R.curry(function(path, val, obj) {
    return R.eq(val, R.path(path, obj));
}); 

And then use it like so:

 var rejectThis = 'userName1';
 var myFilter = R.useWith(R.reject, pathEq('providers.github.login'):
 var filteredList = myFilter(rejectThis, users);
like image 195
Ludwig Magnusson Avatar answered Nov 08 '22 07:11

Ludwig Magnusson


Extending the solution from @LudwigMagnusson, a bit, you could do this:

// terrible name, but I'm never good at that.
var rejectPathVal = R.curry(function(path, val, list) {
    return R.reject(R.pathEq(path, val), list);
});

var filteredList = rejectPathVal('providers.github.login', 'userName1', list);

And of course you could then use it like:

var myFilter = rejectPathVal('providers.github.login', 'userName1');
// ...
var filteredList = myFilter(list);

or in any way you choose, given that it's fully curried. Although as Ludwig pointed out, pathEq is not in the released version of Ramda, you can get it by downloading the HEAD version from Github, or you could use the version Ludwig supplied above.


But I want to question your requirements a bit. I applaud your attempt to move to a more functional style. I'm one of the authors of Ramda, and think it's a great choice for a library, but this seems to be unnecessary:

Make the implementation as short as possible, relying on existing functions in the Ramda library as much as possible.

I would suggest that goals of readability should always trump goals of terseness. Granted, elegance and readability are often tied together with brevity, but "as short as possible" should never be a driving goal.

like image 1
Scott Sauyet Avatar answered Nov 08 '22 08:11

Scott Sauyet


if you don't need to create the function point-free, you can simply:

var removeUserFromList= function(name, list) {
    return R.reject(pathEq('providers.github.login', name), list);
}
console.log(removeUserFromList('username1', users));

using @Ludwig Magnussen's pathEq function.

like image 1
Buzz de Cafe Avatar answered Nov 08 '22 06:11

Buzz de Cafe