These are chat archives for ramda/ramda

26th
Feb 2018
Casey Link
@Ramblurr
Feb 26 2018 07:47
is there a function for "joining" two lists of objects based on a common key?
mergeWithKey jumped out but doesn't seem appropriate here
Casey Link
@Ramblurr
Feb 26 2018 08:07
hm i guess i'll build it with indexBy, merge and mergeWith
Joey Figaro
@joeyfigaro
Feb 26 2018 14:19
@Ramblurr Did you end up finishing that?
@Ramblurr I'm looking to do the exact same thing.
Casey Link
@Ramblurr
Feb 26 2018 14:31
@joeyfigaro Yea, here
Julien Gonzalez
@customcommander
Feb 26 2018 14:45
@franciscotln I didn’t think of using R.find. I did look at your suggestion but I’m not very keen on executing a function twice if I can avoid it.
Gant Laborde
@GantMan
Feb 26 2018 14:50
I have an interesting problem. I need to demote a PATH option. It's easy for me to remove it 100%, but what I really want to do, is take it and put it at the BOTTOM of the list.
This one removes it: https://goo.gl/QESUaq
But I can't fathom how to take it away from (usually the front, but not guaranteed) and demote it to the back if found.
Mike Lambert
@lax4mike
Feb 26 2018 14:52
maybe you can use sort?
Gant Laborde
@GantMan
Feb 26 2018 14:54
O maybe sort will be best!
Mike Lambert
@lax4mike
Feb 26 2018 14:55
or you could possibly use findIndex
Joey Figaro
@joeyfigaro
Feb 26 2018 14:58
@Ramblurr Awesome, man. Can't thank you enough.
Gant Laborde
@GantMan
Feb 26 2018 15:05
@lax4mike so I'm close, but I totally screwed up the order of my PATH, not sure how
Mike Lambert
@lax4mike
Feb 26 2018 15:05
yeah, i guess the sort should be stable, but i'm not sure if that guarenteed
but maybe you just need to handle a in the sort
something like this
const nmSort = (a, b) => R.contains("node_modules", b) ? -1 : R.contains("node_modules", a) ? 1 : 0;
Mike Lambert
@lax4mike
Feb 26 2018 15:11
or maybe this is better
R.sort(R.ascend(R.contains("node_modules"))),
i think R.ascend does what I did manually there
Gant Laborde
@GantMan
Feb 26 2018 15:12
So, I put in const nmSort = (a, b) => -1 to make sure it's deterministic, and it sort of randomizes the path. So I'm thinking the way sort breaks the problem up is non-deterministic.
Mike Lambert
@lax4mike
Feb 26 2018 15:12
well, sort needs a case for when your target element is a and when your target element is b
const nmSort = (a, b) => 0 should be deterministic
hmm yeah, the R.ascend doesn't look stable
probably because it's returning a boolean...
tldr; javascript sort isn't stable
maybe find is a better approach
const demoteNM = (path) => {
  const list = R.split(":", path);
  const el = R.find(R.contains("node_modules"), list);

  return R.compose(
    R.append(el),
    R.reject(R.equals(el))
  )(list);
}
Gant Laborde
@GantMan
Feb 26 2018 15:24
how about this solution?
let originalArray = pathy.split(':')
let cleanArray = reject(contains('node_modules'), originalArray)
concat(cleanArray, difference(originalArray, cleanArray)).join(':')
seems like an abuse of resources, but it's simple.
I really liked my pipe solution from earlier, but I can't get the flow to keep 2 things, so this seems reasonable.
Mike Lambert
@lax4mike
Feb 26 2018 15:27
you might be able to use R.converge
not sure if it would be cleaner though...
Gant Laborde
@GantMan
Feb 26 2018 15:31
thanks for your help mike! I love this channel
Mike Lambert
@lax4mike
Feb 26 2018 15:31
:thumbsup:
Mike Lambert
@lax4mike
Feb 26 2018 16:05
i like your last solution because it will handle if you have 2 paths that contain node_modules
Casey Link
@Ramblurr
Feb 26 2018 16:15
@joeyfigaro no problem, its quite a handy function. I've used it several times today already.. a dash of node and ramda is becoming one of my go to tools for munging data files
Jonas Windey
@jonaswindey
Feb 26 2018 16:30
is there a way to use the getTitle function without passing the id and the list?
Mike Lambert
@lax4mike
Feb 26 2018 16:32
how do you want to use it?
Jonas Windey
@jonaswindey
Feb 26 2018 16:34
like in the example
since the id being sent is passed to the findById method
Mike Lambert
@lax4mike
Feb 26 2018 16:37
i guess you can do it if you make findById curried
const findById = R.curry((id, list) => find(propEq('id', id), list));
const getTitle = findById(R.__, userTitles)

getTitle(1)
Jonas Windey
@jonaswindey
Feb 26 2018 16:40
ah yes that was it, I had to flip the arguments
tried it with curry but forgot the __ (or flip)
Mike Lambert
@lax4mike
Feb 26 2018 16:40
i guess you can also manually curry it with the arguments fliped
const findById = list => id => find(propEq('id', id), list)
const getTitle = findById(userTitles)

getTitle(1)
or just do it like you were doing it
const getTitle = id => findById(id)(userTitles)
Jonas Windey
@jonaswindey
Feb 26 2018 16:42
great tip, thanks
yea but I like to have the function callers as short as possible since the id will be everywhere
Jonas Windey
@jonaswindey
Feb 26 2018 17:10
question, in a pipe method, is there a way to access the original object?
I know I lose the object since I prop('attributeTypeId') but how would I best handle this case?
Francisco
@franciscotln
Feb 26 2018 17:10
@customcommander I don't get this part "I’m not very keen on executing a function twice", what do you mean by that?
The solution I gave to you using R.find will just iterate over the array and execute every function checking it's result to see if it's an empty string, the first one that's not empty will be returned and the iteration is aborted. So yes, you have to call the function to check what it returns and assign the result of R.find to a variable to be used later. I don't know how you'd like to check it but transducer doesn't have much to do with it in my understanding.
Mike Lambert
@lax4mike
Feb 26 2018 17:15
@jonaswindey I struggle with this too, there are other "combinator" functions, like converge that might be able to help with situations like these, but i'm still a bit foggy on those. However, in your case, you could check out propEq and use that in each of the cond branches
const getValue = cond([
  [propEq('attributeTypeId', 1), prop('valueText')],
  [propEq('attributeTypeId', 2), prop('valueNumber')],
  [T, always('no type found')]
])
Brad Compton (he/him)
@Bradcomp
Feb 26 2018 17:23
@jonaswindey in addition to the propEq solution, another option is to wrap the pipe in a function call so that you have access to the object via a closure.
const pipeWithObjAccess = (obj) => pipe(
  /*you can now access `obj` in here*/
)(obj);
functionalStoic
@functionalStoic
Feb 26 2018 17:28
Is there a shortcut key to comment out a line or selected text in the Ramda REPL?
Jonas Windey
@jonaswindey
Feb 26 2018 17:33
thanks @Bradcomp and @lax4mike
Matthew Willhite
@miwillhite
Feb 26 2018 18:07
unrelated: anybody here have a favorite API mocking service? I’m looking to be able to define a structure and have it insert random data
Vesa Karvonen
@polytypic
Feb 26 2018 18:15

@jonaswindey @Bradcomp @lax4mike I recently added a condOf lens constructor to Partial Lenses, because I noticed that it was typical to have conditions on some property of the target object. Using condOf of Partial Lenses one can write:

const object1 = {attributeTypeId: 1, valueText: 'text value'}
const object2 = {attributeTypeId: 2, valueNumber: 123}
const object3 = {attributeTypeId: 3}

L.get(
  L.condOf(
    'attributeTypeId',
    [R.equals(1), 'valueText'],
    [R.equals(2), 'valueNumber'],
    [R.always('no type found')]
  ),
  object2
)

Here is the above in a playground.

I mention this because a similar condOf with an additional argument to select the property on which to do the conditions would likely make sense in Ramda.

Julien Gonzalez
@customcommander
Feb 26 2018 20:34
@franciscotln Thanks for your explanation. I spent a bit more time today and found a solution with transduce actually:
const a = () => '';
const b = () => 'foo';
const c = () => 'bar';

const fns = [a, b, c];

R.transduce(R.map(R.applyTo(1)), R.pipe(R.concat, R.unless(R.isEmpty, R.reduced)), '', fns);
//=> 'foo'
Francisco
@franciscotln
Feb 26 2018 22:49
R.map(R.call) should be enough then
Julien Gonzalez
@customcommander
Feb 26 2018 22:51
Indeed
Francisco
@franciscotln
Feb 26 2018 23:00
const fns = [
  () => '',
  () => 'foo',
  () => 'bar'
];

R.reduce((acc, curr) => acc || curr(), '', fns);
I think that's more "human friendly" @customcommander :D
As you wanted: the function is called only once and when it finds the first function that returns a non-empty string it doesn't call the remaining functions
Francisco
@franciscotln
Feb 26 2018 23:05
in any case I don't think this solution is better than using R.find because this will iterate over the whole collection although it doesn't call all the functions inside the collection, but still, if you have lots of items in this array that's not very optimal. R.find would abort the iteration after finding the first function returning a non-empty string, assign it to a constant and then call it to get the value. Yes, you call the same function twice but at least you don't have to go through the whole collection to get the result.
That's just my opinion : - )
Julien Gonzalez
@customcommander
Feb 26 2018 23:07
Well wouldn’t R.reduced stop the iteration though?
Francisco
@franciscotln
Feb 26 2018 23:08
no
R.reduce, as the name suggests, has to reduce a collection to a value
it doesn't stop the execution
Julien Gonzalez
@customcommander
Feb 26 2018 23:09
R.reduced (with d at the end)
The doc of R.transduce says iteration may be stopped early with the R.reduced function.
Francisco
@franciscotln
Feb 26 2018 23:09
oh I see, Reduced
yes, true
but be careful with R.reduced :D
the docs suggest the same
Julien Gonzalez
@customcommander
Feb 26 2018 23:11
My understanding is that we shouldn’t try to access the internals of it and leave that to Ramda.
So as long as I don’t try to do R.reduced(‘foo’)[‘@@whatever/value’] I should be fine right?
Francisco
@franciscotln
Feb 26 2018 23:13
Yes, it should be
Julien Gonzalez
@customcommander
Feb 26 2018 23:17
Thx
I wanted to get familiar with transducers because I may have to do more transformations after running the functions.