function composition in ramda.js - javascript

Given the following:
var xs = [{a: 1}, {a: 2}, {a: 3}];
R.findIndex(R.propEq('a', 2))(xs); //=> 1
R.findIndex(R.propEq('a', 4))(xs); //=> -1
How do I create a new function that does not bind propEq immediately.
I thought curry might do it.
var myfn = R.findIndex(R.propEq);
myfn('a', '2')(xs); // => 1
I tried curry, but I don't have it quite correct.
var myfn = R.findIndex(R.curry(R.propEq)); // functional programming is rusty - this is not currect

Well, my first thought is that simply being explicit would be best here:
const findByProp = curry((key, val, xs) => findIndex(propEq(key, val), xs));
const xs = [{a: 1, b: 10}, {a: 2, b: 20}, {a: 3, b: 30}];
findByProp('a', 1, xs); //=> 0
findByProp('a', 2)(xs); //=> 1
findByProp('b')(30)(xs); //=> 2
There might be some way to make this points-free using useWith or converge or Sanctuary's S combinator, but they would probably in the end not be as readable as this.
You can see this in action on the Ramda REPL.

Related

Setting variables based off an object

I have an object which could include a mix of properties e.g.
{a: 1}, {b: 4}, {c: 2}, {a: 3, b: 1}
it will be a key with a count value next to it.
I'd like to set a bunch of variables depending on which key names are in the object, for instance:
aOnly = {a: 1}, mixOfAB = {a: 3, b: 1}
I'm using this logic in a function which will eventually return a string value. What's the best way to operate on this object, I tried using a switch but it didn't work so well. I could use a large number of if/else statements but is there something more neater?
You could do something like this:
vars = {}
function setVariable(obj) {
keys = Object.keys(obj)
name = keys.length == 1 ? keys[0] + 'Only' : 'mixOf' + keys.join('').toUpperCase()
vars[name] = obj
}
setVariable({a: 1})
console.log(vars)
setVariable({b: 4})
console.log(vars)
setVariable({c: 2})
console.log(vars)
setVariable({a: 3, b: 1})
console.log(vars)

Point-free composition of lenses in Ramda.js

I am trying to compose functions that return lenses, to produce a new lens, and do it in a point-free style.
This is probably a more general question about function composition. Lenses are just a case-study. I am not interested in lenses specifically, but I want to know the general pattern for how to compose these functions in a point-free way.
const obj = {a: {x: 0}, b: {x: 42}};
// this won't work, but I want it to work
const pointFreeComposedLens = R.compose(R.lensProp, R.lensProp('x'));
R.view(pointFreeComposedLens('a'), obj); // returns 'undefined'
// this works
const pointyComposedLens = key => R.compose(R.lensProp(key), R.lensProp('x'));
R.view(pointyComposedLens('a'), obj); // returns '0'
What is the pattern for composing functions so that I don't need to keep re-writing the arguments for the first function in the composition pipeline?
For an egregious example:
const deepLens = (a, b, c) => R.lensPath([a, b, c]);
// This works, but is tedious & verbose
const extraDeep = (a, b, c, x) => R.compose(deepLens(a,b,c), R.lensProp(x));
const gammaDeep = (a, b, c, y) => R.compose(deepLens(a,b,c), R.lensProp(y));
// Doesn't work, but it would be nicer to write:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
// and call it like so:
R.view(extraDeep('a','b','c','x'), obj);
I know you're looking at lenses only as an example, but here is one way to get something like the behavior I think you want from them.
const {lensPath, compose, lens, view} = R
const deepLens = (a, b, c) => lensPath([a, b, c]);
const deeper = (lens, ...args) => compose(lens, lensPath(args))
const cLens = deepLens('a', 'b', 'c')
const obj = {a: {b: { c: {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}}}}
console.log(view(cLens, obj)) //=> {d: 1, e: 2, f: {g: 3, h: 4, i: {j: 5, k: 6}}}
console.log(view(deeper(cLens, 'f', 'g'), obj)) //=> 3
const fLens = deeper(cLens, 'f')
console.log(view (fLens, obj)) //=> {g: 3, h: 4, i: {j: 5, k: 6}}
const jLens = deeper(cLens, 'f', 'i', 'j')
// or jLens = deeper(fLens, 'i', 'j')
console.log(view(jLens, obj)) //=> 5
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
As to the broader composition question, lenses are generally a special case for a library like Ramda, as the composition is in the opposite order than usually expected. (The technical reasons are too much to go into here.)
But that's why this doesn't work:
const extraDeep = x => R.compose(deepLens, R.lensProp(x));
Ramda does allow the first function in a composition chain (rightmost in compose, leftmost in pipe to receive additional arguments. But when the composition order is reversed with lens composition, it doesn't do what you might like.
So if you are having similar issues with composition in another context, please open a separate question. I'd be curious to see what you're looking for.
Rest parameters will shorten the code to:
const extraDeep = (...rest) => last => R.compose(deepLens(...rest), R.lensProp(last))(rest.pop());
but I'm not sure if that is really elegant.
If your intention is to write a function that accepts a path and an object,
then path already exists:
R.path(['a', 'b'], {a: {b: 10}}); //=> 10
If you're interested in removing some parameters in some of your functions, deepLens could be rewritten as follow:
const deepLens = R.unapply(R.lensPath);
This point-free version has the added benefit that it is not limited to just three parameters. It will work with any number of parameters:
deepLens('a', 'b'); //=> R.lensPath(['a', 'b']);
deepLens('a', 'b', 'c'); //=> R.lensPath(['a', 'b', 'c']);
deepLens('a', 'b', 'c', 'd'); //=> R.lensPath(['a', 'b', 'c', 'd']);

Javascript copy array of properties to another object (one-liner) [duplicate]

This question already has answers here:
One-liner to take some properties from object in ES 6
(13 answers)
Closed 5 years ago.
This is obviously straight-forward using traditional loops, but I'm curious if anyone can think of a nice, compact way of doing it with destructuring and the spread operator.
For example, let's say I have
const foo = { a: 1, b: 2, c: 3, d: 4 };
const list = ['a', 'd'];
I'd like to create bar = { a: 1, d: 4 }.
You could do something like
const bar = {};
list.forEach((p) => { bar.p = list.p; });
But I'm wondering if anyone has a slick one-liner using ES2015+. For example, you can do const { b, c, ...bar } = foo, but that's if you have the inverse known prior to runtime.
While the solution ideally would support a dynamic list of properties in an array, one with a statically known list is better than nothing. (For example, const bar = ({{ a, d }} = foo)
The best I think you'll be able to do is with Array#reduce:
const foo = { a: 1, b: 2, c: 3, d: 4 };
const list = ['a', 'd'];
const bar = list.reduce((o, k) => (o[k] = foo[k], o), {})
console.log(bar)

Join Array of Objects by Property using lodash

Is there a way using lodash or another library to join an array of objects?
I'm looking for a readymade function not a for loop.
For example:
[{a: 1}, {a:3}, {a: 4}]
//Run a function by specifing the property a and setting "," as the delimeter
Get 1,3,4
Here is your lodash answer
var arr = [{a: 1}, {a:3}, {a: 4}];
var s = _.map(arr, 'a').join(',');
//s == '1,2,3,4'
You don't need lodash for this, you can just use map and join:
let collection = [{a: 1}, {a:3}, {a: 4}];
alert(collection.map(item => item.a).join(','));

Javascript assignation issue

I was trying to change the structure of a Javascript object and I don't understand the results I am receiving from the logs.
I have the following object: a = {e: 1, f: 2}
And I want to move it to a.b
If I do a.b = a then I receive these results:
console.log(a) // {e: 1, f: 2}
console.log(a.b) // {e: 1, f: 2}
While I am expecting something like this:
console.log(a) // {b: {e: 1, f: 2}}
console.log(a.b) // {e: 1, f: 2}
Can someone explain me why this is happening?
Assigning a value in JS doesn't move it, it copies it.
You are adding a b property to the existing object.
It isn't shown in the log because console.log protects itself against infinite recursion by not displaying the property.
a.b = a simply assigns a.b as a reference to a, which causes a to become a recursive object:
var a = {e: 1, f: 2};
a.b = a;
console.log(a.e, a.f); //1 2
console.log(a.b.e, a.b.f); //1 2
console.log(a.b.b.e, a.b.b.f); //1 2
console.log(a.b.b.b.e, a.b.b.b.f); //1 2
To actually move a's properties into a.b, you'll need to overwrite the existing object, assigning a new property b to its existing value:
var a = {e: 1, f: 2};
a = {b: a};
console.log(a); //{b: {e: 1, f: 2}}

Categories