Difference between curry and curryRight in Lodash - javascript

What is the difference between curry and curryRight in Lodash?
Is just the application order of the provided arguments switched from f(a,b,c) which applies to f(a) -> f(b) -> f(c) to f(a,b,c) which then applies to f(c) -> f(b) -> f(a)?
I already looked into the Lodash documentation but that didn‘t helped me.

From the documentation:
var abc = function(a, b, c) {
return [a, b, c];
};
var curried = _.curryRight(abc);
curried(3)(2)(1);
// => [1, 2, 3]
curried(2, 3)(1);
// => [1, 2, 3]
curried(1, 2, 3);
// => [1, 2, 3]
The first example is simple. The order of the arguments is reversed (in comparison to _.curry).
The second and third one can perhaps be confusing.
In the third example we see that the order of the arguments is NOT reversed. That is because only the currying is applied in reverse. In other words the parentheses are applied in the reverse order, but what is inside of the parentheses sustains the original order.
Compare this to the result of _.curry(_.flip(f)):
var abc = function(a, b, c) {
  return [a, b, c];
};
var curried = _.curry(_.flip(abc), 3);
 
curried(3)(2)(1);
// => [1, 2, 3]
curried(3, 2)(1);
// => [1, 2, 3]
curried(3, 2, 1);
// => [1, 2, 3]
As you can see the result is different. Now the order of the arguments is reversed totally in all the examples.
Btw notice that for some reason I needed to specify the arity to 3 in _.curry(_.flip(abc), 3);. I don't know why but it causes an exception without that.

Related

Why the first item in native javascript function sort() - is the second in my array?

When I was trying to understand how the sort(i mean native js) function works (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
and used their function:
let numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => a - b);
console.log(numbers);
I added a console.log, but the first element was the second:
let numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => console.log('a - is - '+ a));
console.log(numbers);
Why?
Thanks in advance!
You neglected to return anything (other than undefined) from your logging version which is why it is failing to sort. You also only log one of the values.
let numbers = [4, 2, 5, 1, 3];
numbers.sort((a, b) => {
console.log('a: ' + a + ' - b: ' + b);
return a - b
});
console.log(numbers);
Taking a look at the spec doesn't explicitly state why the items are passed in a seemingly reversed order and seems to be open for interpretation by JS engine implementors. As such I might expect to see different behaviour with other JS engines although it's just as likely that they all implement this the same way.

Sorting array with sort function [duplicate]

This question already has answers here:
How does Javascript's sort() work?
(8 answers)
How does sort function work in JavaScript, along with compare function
(7 answers)
How does JavaScript's sort (compareFunction) work? [duplicate]
(3 answers)
Closed 1 year ago.
I got question today, that I couldn't answer. I would appreciate if you could just explain it to me. Why my array doesn't output [1, 2, 3, 4, 5] but only [2, 3, 4, 5]?
This is the code:
let numbers = [1, 2, 3, 4, 5]
let order = numbers.sort((a, b) => {
console.log(a);
});
But when I use this code, it works perfectly fine
let numbers = [1, 2, 3, 4, 5]
let order = numbers.sort((a, b) => {
return a;
})
console.log(order);
It doesn't output [2, 3, 4, 5] it outputs 2, 3, 4 and 5 each in a separate step of the iteration. If you also log order you'll see that the array still contains [1, 2, 3, 4, 5]. The comparator function receives two elements of the array that it compares to each other. That way it knows in which order those elements should be. If you only log a and not b, you'll wont see all the information that is passed to the comparator. If you log both a and b, you'll see that also 1 is passed, to parameter b.
let numbers = [1, 2, 3, 4, 5]
let order = numbers.sort((a, b) => {
console.log('Comparing', a, b);
});
console.log('Final result', order);
Keep in mind that the comparator function should return either a positive number when a is greater than b, a negative number when a is less than b and 0 when both elements are equal to each other. The above comparator function doesn't return any value at all, so it might not do what you expect it to do.
(Also your snippet that "works perfectly fine" doesn't follow that contract. It returns a positive number for each element, so it is basically saying that every element is greater than every other element.)
The sort() method sorts the elements of an array in place and returns the sorted array.
[1, 2, 3, 4, 5].sort((a, b) => {
console.log({a, b}); // a is secondItem, b is firstItem of an array
return -1; // return -ve value for DESC and truthy value for ASC order
});
Output will be
{a: 2, b: 1}
{a: 3, b: 2}
{a: 4, b: 3}
{a: 5, b: 4}
sort output: [5, 4, 3, 2, 1]

Javascript recursion: pull all unique combinations of single items from N arrays of M length

I am looking to create a recursive function (or use loops), to select all possible combinations of single items of N arrays, each having M length.
I want to pull out each combination and find the product of the items from the arrays and store the result. So in other words, the order of the items pulled out doesn't matter (for the example, 1, 1, 4 pulled from the first index starting with array1 would be considered the same as 4, 1, 1 pulled from the first index starting with array3 and working backwards).
//Example:
//in this case, N = 3 and M = 5, 3, 4 for array1, array2, and array3, respectively
array1 = [1, 3, 5, 6, 7];
array2 = [1, 5, 3];
array3 = [4, 3, 7, 9];
//Example output using arrays above:
[1, 1, 4]
[3, 1, 4]
[5, 1, 4]
[6, 1, 4]
[7, 1, 4]
[1, 5, 4]
[1, 3, 4]
[3, 5, 4]
//etc...
I expect the output of each recursive call to be one item from each Array, resulting in a unique combination of items.
For example, each call would output an array of N length, with one value from each array. The function should run until all unique combinations have been looked at.
UPDATE: to clarify, the final end solution that I am trying to get at is to find the Minimum product, by selecting one item from each array and multiplying them together. But I also need to evaluate, manipulate and store each combination, before determining this minimum.
Cou could get the cartesian product first and then get unique products from this values.
The raw array contains possible duplicates.
const multiply = (a, b) => a * b;
var array1 = [1, 3, 5, 6, 7],
array2 = [1, 5, 3],
array3 = [4, 3, 7, 9],
data = [array1, array2, array3],
raw = data.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), [])),
unique = Array.from(new Set(raw.map(a => a.reduce(multiply))));
console.log(unique);
console.log(raw.map(a => a.join(' ')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
I prefer to write this sort of thing as a composition of functions. I'm a big fan of Ramda (disclaimer: I'm a Ramda author) and with Ramda, this is a one-liner 1:
const uniqueProduct = pipe (xprod, map (product), unique)
Of course you wouldn't want to pull in an external library for a single simple problem, but it's also easy to write our own versions of the functions used here:
// Utility functions
const pipe = (...fns) => (args) =>
fns .reduce ((a, f) => f (a), args)
const map = (fn) => (xs) =>
xs.map(fn)
const product = (xs) =>
xs .reduce ((a, x) => a * x, 1)
const crossproduct = (xss) =>
xss.reduce(
(ps, xs) => ps.reduce((r, p) => [...r, ...(xs.map((x) => [...p, x]))], []),
[[]]
)
const unique = (xs) =>
Array .from (new Set (xs))
// Main function
const uniqueProduct = pipe (crossproduct, map (product), unique)
// Demonstration
const data = [[1, 3, 5, 6, 7], [1, 5, 3], [4, 3, 7, 9]]
console .log (
uniqueProduct (data)
)
Every function here, except for uniqueProduct is common enough that there's already a version available in Ramda. But these versions are also potentially useful across a great deal of your code. And outside crossproduct, they are trivial-to-write functions.
Note that there is no difference here in algorithm from Nina Scholz's answer; it's only structured differently. I like the fact that, by storing the common functions in my own library or by using a public one, this code can be written so simply.
1 This is actually a bit of an exaggeration. Ramda's xprod function only works on two arrays; I happen to keep handy one that works on an array of arrays in my own personal utility library built atop Ramda.

How to navigate and pull from an object in JavaScript

I am being given the function call destroyer([1, 2, 3, 1, 2, 3], 2, 3);. I want to be able to pull from the last 2, 3 part after the initial object, but I do not know how to go about this.
return arr[6]; and return arr[1][0] both return nothing. I am expecting to see 2 or 2, 3 (Last two numbers)
I tried researching Property Accessors, but I think I was looking in the wrong place for my answer.
Here's my full code:
function destroyer(arr) {
return arr;
}
destroyer([1, 2, 3, 1, 2, 3], 2, 3);
Instead of getting the first array [1,2,3,1,2,3]
I want to get the parts after the array:
[1,2,3,1,2,3],2,3
You're destroyer function is only taking one argument, but you're passing it 3.
You have two options:
Use arguments to get an array-like of all the passed arguments, you'll then need to combine that with a method like slice to get only the second and third arguments. Additionaly since arguments isn't technically an array, you need to convert it to one before you can call a method like slice. My example uses Array.from however that is only available on newer browsers.
function destroyer(arr) {
return Array.from(arguments).slice(1,3);
}
console.log('Result: ', destroyer([1, 2, 3, 1, 2, 3],2,3));
Add additional parameters to your function definition. This is probably easier if you know you'll have exactly 3 arguments. And there are far fewer gotchas compared to using the magic arguments variable.
function destroyer(a, b, c) {
return [b, c];
}
console.log('Result: ', destroyer([1, 2, 3, 1, 2, 3], 2, 3));
try use arguments
example
function destroyer(){var arr = []; arr.push(arguments[1]);arr.push(arguments[2]); return arr};

Can't wrap my head around "lift" in Ramda.js

Looking at the source for Ramda.js, specifically at the "lift" function.
lift
liftN
Here's the given example:
var madd3 = R.lift(R.curry((a, b, c) => a + b + c));
madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
So the first number of the result is easy, a, b, and c, are all the first elements of each array. The second one isn't as easy for me to understand. Are the arguments the second value of each array (2, 2, undefined) or is it the second value of the first array and the first values of the second and third array?
Even disregarding the order of what's happening here, I don't really see the value. If I execute this without lifting it first I will end up with the arrays concatenated as strings. This appears to sort of be working like flatMap but I can't seem to follow the logic behind it.
Bergi's answer is great. But another way to think about this is to get a little more specific. Ramda really needs to include a non-list example in its documentation, as lists don't really capture this.
Lets take a simple function:
var add3 = (a, b, c) => a + b + c;
This operates on three numbers. But what if you had containers holding numbers? Perhaps we have Maybes. We can't simply add them together:
const Just = Maybe.Just, Nothing = Maybe.Nothing;
add3(Just(10), Just(15), Just(17)); //=> ERROR!
(Ok, this is Javascript, it will not actually throw an error here, just try to concatenate thing it shouldn't... but it definitely doesn't do what you want!)
If we could lift that function up to the level of containers, it would make our life easier. What Bergi pointed out as lift3 is implemented in Ramda with liftN(3, fn), and a gloss, lift(fn) that simply uses the arity of the function supplied. So, we can do:
const madd3 = R.lift(add3);
madd3(Just(10), Just(15), Just(17)); //=> Just(42)
madd3(Just(10), Nothing(), Just(17)); //=> Nothing()
But this lifted function doesn't know anything specific about our containers, only that they implement ap. Ramda implements ap for lists in a way similar to applying the function to the tuples in the crossproduct of the lists, so we can also do this:
madd3([100, 200], [30, 40], [5, 6, 7]);
//=> [135, 136, 137, 145, 146, 147, 235, 236, 237, 245, 246, 247]
That is how I think about lift. It takes a function that works at the level of some values and lifts it up to a function that works at the level of containers of those values.
Thanks to the answers from Scott Sauyet and Bergi, I wrapped my head around it. In doing so, I felt there were still hoops to jump to put all the pieces together. I will document some questions I had in the journey, hope it could be of help to some.
Here's the example of R.lift we try to understand:
var madd3 = R.lift((a, b, c) => a + b + c);
madd3([1,2,3], [1,2,3], [1]); //=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
To me, there are three questions to be answered before understanding it.
Fantasy-land's Apply spec (I will refer to it as Apply) and what Apply#ap does
Ramda's R.ap implementation and what does Array has to do with the Apply spec
What role does currying play in R.lift
Understanding the Apply spec
In fantasy-land, an object implements Apply spec when it has an ap method defined (that object also has to implement Functor spec by defining a map method).
The ap method has the following signature:
ap :: Apply f => f a ~> f (a -> b) -> f b
In fantasy-land's type signature notation:
=> declares type constraints, so f in the signature above refers to type Apply
~> declares method declaration, so ap should be a function declared on Apply which wraps around a value which we refer to as a (we will see in the example below, some fantasy-land's implementations of ap are not consistent with this signature, but the idea is the same)
Let's say we have two objects v and u (v = f a; u = f (a -> b)) thus this expression is valid v.ap(u), some things to notice here:
v and u both implement Apply. v holds a value, u holds a function but they have the same 'interface' of Apply (this will help in understanding the next section below, when it comes to R.ap and Array)
The value a and function a -> b are ignorant of Apply, the function just transforms the value a. It's the Apply that puts value and function inside the container and ap that extracts them out, invokes the function on the value and puts them back in.
Understanding Ramda's R.ap
The signature of R.ap has two cases:
Apply f => f (a → b) → f a → f b: This is very similar to the signature of Apply#ap in last section, the difference is how ap is invoked (Apply#ap vs. R.ap) and the order of params.
[a → b] → [a] → [b]: This is the version if we replace Apply f with Array, remember that the value and function has to be wrapped in the same container in the previous section? That's why when using R.ap with Arrays, the first argument is a list of functions, even if you want to apply only one function, put it in an Array.
Let's look at one example, I'm using Maybe from ramda-fantasy, which implements Apply, one inconsistency here is that Maybe#ap's signature is: ap :: Apply f => f (a -> b) ~> f a -> f b. Seems some other fantasy-land implementations also follow this, however, it shouldn't affect our understanding:
const R = require('ramda');
const Maybe = require('ramda-fantasy').Maybe;
const a = Maybe.of(2);
const plus3 = Maybe.of(x => x + 3);
const b = plus3.ap(a); // invoke Apply#ap
const b2 = R.ap(plus3, a); // invoke R.ap
console.log(b); // Just { value: 5 }
console.log(b2); // Just { value: 5 }
Understanding the example of R.lift
In R.lift's example with arrays, a function with arity of 3 is passed to R.lift: var madd3 = R.lift((a, b, c) => a + b + c);, how does it work with the three arrays [1, 2, 3], [1, 2, 3], [1]? Also note that it's not curried.
Actually inside source code of R.liftN (which R.lift delegates to), the function passed in is auto-curried, then it iterates through the values (in our case, three arrays), reducing to a result: in each iteration it invokes ap with the curried function and one value (in our case, one array). It's hard to explain in words, let's see the equivalent in code:
const R = require('ramda');
const madd3 = (x, y, z) => x + y + z;
// example from R.lift
const result = R.lift(madd3)([1, 2, 3], [1, 2, 3], [1]);
// this is equivalent of the calculation of 'result' above,
// R.liftN uses reduce, but the idea is the same
const result2 = R.ap(R.ap(R.ap([R.curry(madd3)], [1, 2, 3]), [1, 2, 3]), [1]);
console.log(result); // [ 3, 4, 5, 4, 5, 6, 5, 6, 7 ]
console.log(result2); // [ 3, 4, 5, 4, 5, 6, 5, 6, 7 ]
Once the expression of calculating result2 is understood, the example will become clear.
Here's another example, using R.lift on Apply:
const R = require('ramda');
const Maybe = require('ramda-fantasy').Maybe;
const madd3 = (x, y, z) => x + y + z;
const madd3Curried = Maybe.of(R.curry(madd3));
const a = Maybe.of(1);
const b = Maybe.of(2);
const c = Maybe.of(3);
const sumResult = madd3Curried.ap(a).ap(b).ap(c); // invoke #ap on Apply
const sumResult2 = R.ap(R.ap(R.ap(madd3Curried, a), b), c); // invoke R.ap
const sumResult3 = R.lift(madd3)(a, b, c); // invoke R.lift, madd3 is auto-curried
console.log(sumResult); // Just { value: 6 }
console.log(sumResult2); // Just { value: 6 }
console.log(sumResult3); // Just { value: 6 }
A better example suggested by Scott Sauyet in the comments (he provides quite some insights, I suggest you read them) would be easier to understand, at least it points the reader to the direction that R.lift calculates the Cartesian product for Arrays.
var madd3 = R.lift((a, b, c) => a + b + c);
madd3([100, 200], [30, 40, 50], [6, 7]); //=> [136, 137, 146, 147, 156, 157, 236, 237, 246, 247, 256, 257]
Hope this helps.
lift/liftN "lifts" an ordinary function into an Applicative context.
// lift1 :: (a -> b) -> f a -> f b
// lift1 :: (a -> b) -> [a] -> [b]
function lift1(fn) {
return function(a_x) {
return R.ap([fn], a_x);
}
}
Now the type of ap (f (a->b) -> f a -> f b) isn't easy to understand either, but the list example should be understandable.
The interesting thing here is that you pass in a list and get back a list, so you can repeatedly apply this as long as the function(s) in the first list have the correct type:
// lift2 :: (a -> b -> c) -> f a -> f b -> f c
// lift2 :: (a -> b -> c) -> [a] -> [b] -> [c]
function lift2(fn) {
return function(a_x, a_y) {
return R.ap(R.ap([fn], a_x), a_y);
}
}
And lift3, which you implicitly used in your example, works the same - now with ap(ap(ap([fn], a_x), a_y), a_z).

Categories

Resources