Reputation: 186
const R = require('rambda')
export const test = () => {
const data = [1, 2, 3, 4, 5, 6, 7, 8]
const filter = no => no > 5
const map = no => no * 100
// looping 2 times
return data
.filter(filter)
.map(map)
// wird 1 loop
return data.reduce((data, no) => {
if (!filter(no)) return data
data.push(map(no))
return data
}, [])
// I want to do something like this.
return data.map(R.pipe(map, filter))
}
Hello, is it possible to map and filter in one loop using ramda or rambda?
My example:
return data.map(R.pipe(map, filter))
is returning
Array [
600,
700,
800,
true,
true,
true,
true,
true,
true,
true,
true,
]
and I need it to be [600, 700, 800]
Upvotes: 3
Views: 4349
Reputation: 198
Of course it can be.
const expr = R.compose(
R.map(x => x * 100),
R.filter(x => x > 5)
);
const result = expr([1, 2, 3, 4, 5, 6, 7, 8]);
console.log(result);
updated: a one-loop way:
const iter = (acc, x) => (x > 5 && acc.push(x * 100), acc)
const result = R.reduce(iter, [], [1, 2, 3, 4, 5, 6, 7, 8])
Both one-loop or two-loop, execute the same logic, should no difference.
Upvotes: 1
Reputation: 50797
You can do this with Ramda's transducers.
(Disclaimer: I'm a Ramda author)
While a normal composition of regular Ramda functions will loop for every list transformation, a transduced one will run each function in the composition on each iteration. Note that for technical reasons, the composition runs in the reverse order when using transducers.
Not every function is a transducer. The documentation uses this note to indicate one: "Acts as a transducer if a transformer is given in list position." This is included in both map
and filter
. There are several functions that make it easier to work with transducers. into
is one of them.
Still, it might be easier to write your own filterMap
function. Is isn't hard:
const filterMap = curry((f, m, data) => reduce(
(a, i) => f(i) ? append(m(i), a) : a,
[], data))
const {compose, map, filter, into, curry, reduce, append} = R;
const data = [1, 2, 3, 4, 5, 6, 7, 8]
const gt5 = no => {console.log(`filter: ${no}`); return no > 5;}
const times100 = no => {console.log(`map ${no}`); return no * 100;}
console.log('========= Plain composition =========')
const transform1 = compose(map(times100), filter(gt5))
console.log(transform1(data))
console.log('========== With transducers =========')
const transform2 = into([], compose(filter(gt5), map(times100)));
console.log(transform2(data))
console.log('=========== With filterMap ==========')
const filterMap = curry((f, m, data) => reduce((a, i) => f(i) ? append(m(i), a) : a, [], data))
console.log(filterMap(gt5, times100)(data))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.js"></script>
If you want to see how the transducers shine, add a take(2)
to the end of the composition.
These add a great deal of complexity to Ramda's implementations, and there has been some talk of removing them, or trying to find a way to make them optional. But not much has been done toward this.
Upvotes: 15