I like to use Array.prototype.reduce() for several different scenarios in my code, it's pretty straightforward and handy.
Please observe in the 2 different solutions below the reduce() function takes 2 different initial values, in the first case is new Set() and the second is [].
In the below example the code uses reduce() without return keyword - Set one:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.add(c), new Set());
console.log(Array.from(result));
The next example is using still reduce() but here with a return keyword - Array one:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => {
a.find(e => e === c) ? null : a.push(c);
return a;
}, []);
console.log(result);
Question:
So the .add() function for Set returns the Set object itself. The .push() function for Array returns the length of the used Array.
The Set case helps me to shorten the code using .reduce() without return keyword because the above mentioned reason. In my second example I would like to use the solution without return keyword but still with Array somehow.
Is there any workaround solution to get the same result but without using return keyword in the second example? I would like to shorten the code further if possible.
Any help is appreciated.
You could take either the accumulator, if found or concat the element to the accumulator.
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.find(e => e === c) ? a : a.concat(c), []);
console.log(result);
Just to mention, Set takes a complete array with the constructor.
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = Array.from(new Set(data));
console.log(result);
Array#concat can add a new item to an array and returns a new array, so can works similar to Set#add. However, it still needs the conditional operator since you want to either add an element or nothing - for the latter case that's concatenating an array with an empty array:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => a.concat(a.some(e => e === c) ? [] : c), []);
console.log(result);
Alternatively, you can use spread syntax to again combine two arrays:
const data = ['a', 'b', 'c', 'd', 'a', 'k', 'b'];
const result = data.reduce((a, c) => [...a, ...(a.some(e => e === c) ? [] : c)], []);
console.log(result);
Neither of the two is perfect, to be honest. The existence of the conditional operator makes this harder to read when all one line but it's still an option.
I am reading ramda documentation
const 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]
It looks like a really useful function. I can't see what would be a use case for it.
Thanks
This function can only accept numbers:
const add3 = (a, b, c) => a + b + c;
add3(1, 2, 3); //=> 6
However what if these numbers were each contained in a functor? (i.e. a thing that contains a value; an array in the example below)
add3([1], [2], [3]); //=> "123"
That's obviously not what we want.
You can "lift" the function so that it can "extract" the value of each parameter/functor:
const add3Lifted = lift(add3);
add3Lifted([1], [2], [3]); //=> [6]
Arrays can obviously hold more than one value and combined with a lifted function that knows how to extract the values of each functor, you can now do this:
add3Lifted([1, 10], [2, 20], [3, 30]);
//=> [6, 33, 24, 51, 15, 42, 33, 60]
Which is basically what you'd have got if you had done this:
[
add3(1, 2, 3), // 6
add3(1, 2, 30), // 33
add3(1, 20, 3), // 24
add3(1, 20, 30), // 51
add3(10, 2, 3), // 15
add3(10, 2, 30), // 42
add3(10, 20, 3), // 33
add3(10, 20, 30) // 60
]
Note that each array doesn't have to be of the same length:
add3Lifted([1, 10], [2], [3]);
//=> [6, 15]
So to answer your question: if you intend to run a function with different sets of values, lifting that function may be a useful thing to consider:
const results = [add3(1, 2, 3), add3(10, 2, 3)];
is the same as:
const results = add3Lifted([1, 10], [2], [3]);
Functional programming is a long and mathematical topic, in particular the part dealing with monads and cathegory theory in general. But it is worth to take a look at it, here is a funny introduction with pictures.
In short, lift is a function that will take a n-arguments function and will produce a function that takes n wrapped-values and produces another resulting wrapped-value. A lift that take a one-argument function is defined by the following type signature
// name :: f is a wrp-value => function -> wrp-value -> wrp-value
liftA :: Applicative f => (a -> b) -> f a -> f b
Wait... Wrapped-value?
I will introduce briefly Haskell, only to explain this. In haskell, an easy example of wrapped-value is Maybe, Maybe can be a wrapped-value or nothing, that is also a wrapped-value. The following example applies a function to a Maybe containing a value, and a empty Maybe.
> liftA (+ 8) (Just 8)
Just 16
> liftA (+ 8) Nothing
Nothing
The list is also a wrapped-value, and we can apply functions to it. In the second case liftA2 applies two-argument functions to two lists.
> liftA (+ 8) [1,2,3]
[9,10,11]
> liftA2 (*) [1..3] [1..3]
[1,2,3,2,4,6,3,6,9]
This wrapped-value is an Applicative Functor, so from now I will call it Applicative.
Maybe Maybe you are starting to lose interest from this point...
But someone before us has got lost on this topic, finally he survived and published it as an answer to this question.
Lets look at what did he see...
...
He saw Fantasy Land
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).
Fantasy-land is a fancy name to a functional programming spec in
javascript. Ramda follows it.
Apply is our Applicative, a
Functor that implements also an ap method.
A Functor, is something that has the map method.
So, wait... the Array in javascript has a map...
[1,2,3].map((a)=>a+1) \\=> [ 2, 3, 4 ]
Then the Array is a Functor, and map applies a function to all values of it, returning another Functor with the same number of values.
But what does the ap do?
ap applies a list of functions to a list of values.
Dispatches to the ap method of the second argument, if present. Also
treats curried functions as applicatives.
Let's try to do something with it.
const res = R.ap(
[
(a)=>(-1*a),
(a)=>((a>1?'greater than 1':'a low value'))
],
[1,2,3]); //=> [ -1, -2, -3, "a low value", "greater than 1", "greater than 1" ]
console.log(res);
<script src="https://cdn.jsdelivr.net/npm/ramda#0.26.1/dist/ramda.min.js"></script>
The ap method takes an Array (or some other Applicative) of functions an applies it to a Applicative of values to produce another Applicative flattened.
The signature of the method explains this
[a → b] → [a] → [b]
Apply f => f (a → b) → f a → f b
Finally, what does lift do?
Lift takes a function with n arguments, and produces another function that takes n Aplicatives and produces a flattened Aplicative of the results.
In this case our Applicative is the Array.
const add2 = (a, b) => a + b;
const madd2 = R.lift(add2);
const res = madd2([1,2,3], [2,3,4]);
//=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
console.log(res);
// Equivalent to lift using ap
const result2 = R.ap(R.ap(
[R.curry(add2)], [1, 2, 3]),
[2, 3, 4]
);
//=> [3, 4, 5, 4, 5, 6, 5, 6, 7]
console.log(result2);
<script src="https://cdn.jsdelivr.net/npm/ramda#0.26.1/dist/ramda.min.js"></script>
These wrappers (Applicatives, Functors, Monads) are interesting because they can be anything that implements these methods. In haskell, this is used to wrap unsafe operations, such as input/output. It can also be an error wrapper or a tree, even any data structure.
What hasn't been mentioned in the current answers is that functions like R.lift will not only work with arrays but any well behaved Apply1 data type.
For example, we can reuse the same function produced by R.lift:
const lifted = lift((a, b, c) => a + b - c)
With functions as the Apply type:
lifted(a => a * a,
b => b + 5,
c => c * 3)(4) //=> 13
Optional types (dispatching to .ap):
const Just = val => ({
map: f => Just(f(val)),
ap: other => other.map(otherVal => val(otherVal)),
getOr: _ => val
})
const Nothing = {
map: f => Nothing,
ap: other => Nothing,
getOr: x => x
}
lifted(Just(4), Just(6), Just(8)).getOr(NaN) //=> 2
lifted(Just(4), Nothing, Just(8)).getOr(NaN) //=> NaN
Asynchronous types (dispatching to .ap):
const Asynchronous = fn => ({
run: fn,
map: f => Asynchronous(g => fn(a => g(f(a)))),
ap: other => Asynchronous(fb => fn(f => other.run(a => fb(f(a)))))
})
const delay = (n, x) => Asynchronous(then => void(setTimeout(then, n, x)))
lifted(delay(2000, 4), delay(1000, 6), delay(500, 8)).run(console.log)
... and many more. The point here is that anything that can uphold the interface and laws expected of any Apply type can make use of generic functions such as R.lift.
1. The argument order of ap as listed in the fantasy-land spec is reversed from the order supported by name dispatching in Ramda, though is still supported when using the fantasy-land/ap namespaced method.
Basically it is taking a cartesian product and applies a function to each array.
const
cartesian = (a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []),
fn = ([a, b, c]) => a + b + c,
result = [[1, 2, 3], [1, 2, 3], [1]]
.reduce(cartesian)
.map(fn);
console.log(result); // [3, 4, 5, 4, 5, 6, 5, 6, 7]
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)
I am trying to understand the difference between destruct and ...Spread in the following scenario:
Example using ...Spread
function do2(a,b,c){
alert (a+b+c);
}
do2(...[5,3,5]);
Example using Destructing:
function do3({a , b , c}){
alert (a+b+c);
}
do3([5,3,5]);
When do I use each way? Can anyone tell the difference between both ways and which one to use in this scenario? I am still a beginner, so any help would be good.
Operator Spread
Spread example:
const add = (a, b) => a + b;
let args = [3, 5];
add(...args); // same as `add(args[0], args[1])`, or `add.apply(null, args)`
Functions aren't the only place in JavaScript that makes use of comma separated lists - arrays can now be concatenated with ease:
let cde = ['c', 'd', 'e'];
let scale = ['a', 'b', ...cde, 'f', 'g']; // ['a', 'b', 'c', 'd', 'e', 'f', 'g']
Destructuring
Destructuring is a way to quickly extract data out of an {} or [] without having to write much code.
let foo = ['one', 'two', 'three'];
let one = foo[0];
let two = foo[1];
let three = foo[2];
into
let foo = ['one', 'two', 'three'];
let [one, two, three] = foo;
console.log(one); // 'one'
ES6 also supports object destructuring, which might make uses more obvious:
let myModule = {
drawSquare: function drawSquare(length) { /* implementation */ },
drawCircle: function drawCircle(radius) { /* implementation */ },
drawText: function drawText(text) { /* implementation */ },
};
let {drawSquare, drawText} = myModule;
drawSquare(5);
drawText('hello');
The first example assigns a, b c to to elements of passed array at indexes 0, 1, 2, corresponding to the number of elements in the array
function do2(a, b, c){
alert (a + b + c);
}
do2(...[5, 3, 5]);
The second example expects an object as parameter to the function, {a , b , c} destructures the passed object assigning a, b, c as local variables within the function
function do3({a , b , c}){
alert (a + b + c);
}
do3({a:5, b:3, c:5});
See also What is SpreadElement in ECMAScript documentation? Is it the same as Spread operator at MDN?
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.