Reputation: 77
I have a function that returns the filtered result based on string in the object (if it exist or not)
let foo = nodes.reduce((arr, cur) => {
cur.classes.split(' ').filter((el) => {
if (el === 'foo') arr.push(cur)
})
return arr;
}, []);
So it's just return all objects in array that contains 'foo' in classes object This one, for example:
let nodes = [
{node: 'h1', classes: 'foo'},
{node: 'p', classes: 'bar'},
{node: 'p', classes: 'baz xxx'},
{node: 'h2', classes: 'bar baz foo'},
{node: 'ul', classes: 'poop foo'}
]
But my guts tells that the function possible to write more easily and succinctly. Any ideas?
Upvotes: 2
Views: 99
Reputation: 135207
Per usual, @NinaScholz offers a great, straightforward approach. You'd be well-off following her advice.
I personally like to dissect these problem a little further and demonstrate how smaller, reusable functions can be combined to achieve the desired effect. It's my hope that this answer will help you see that functional programming in JavaScript easily extends beyond the built-in prototypal methods.
Comments help you understand types but are completely optional.
// comp :: (b -> c) -> (a -> b) -> (a -> c)
const comp = f => g => x => f (g (x));
// filter :: (a -> Boolean) -> [a] -> [a]
const filter = f => xs => xs.filter(f);
// some :: (a -> Boolean) -> [a] -> Boolean
const some = f => xs => xs.some(f);
// eq :: (String a, Number a) => a -> a -> Boolean
const eq = x => y => y === x;
// nodeClasses :: Node -> [String]
const nodeClasses = ({classes}) => classes.split(' ');
// nodesWithClass :: String -> [Node] -> [Node]
const nodesWithClass = c => filter (comp (some (eq (c))) (nodeClasses));
// nodes :: [Node]
let nodes = [
{node: 'h1', classes: 'foo'},
{node: 'p', classes: 'bar'},
{node: 'p', classes: 'baz xxx'},
{node: 'h2', classes: 'bar baz foo'},
{node: 'ul', classes: 'poop foo'}
];
console.log(nodesWithClass('foo') (nodes));
Upvotes: 1
Reputation: 12637
As an alternative to "filter some", as shown by Nina, a slightly different approach.
Doesn't look that clean, but is more performant (as far as performance matters at such a simple task).
let nodes = [
{node: 'h1', classes: 'foo'},
{node: 'p', classes: 'bar'},
{node: 'p', classes: 'foo-bar'},
{node: 'p', classes: 'baz xxx'},
{node: 'h2', classes: 'bar baz foo'},
{node: 'ul', classes: 'poop foo'}
];
let foo = nodes.filter(node => (' ' + node.classes + ' ').contains(' foo '));
Upvotes: 0
Reputation: 386560
You could use just Array#filter
.
let nodes = [{node: 'h1', classes: 'foo'}, {node: 'p', classes: 'bar'}, {node: 'p', classes: 'baz xxx'}, {node: 'h2', classes: 'bar baz foo'}, {node: 'ul', classes: 'poop foo'}],
foo = nodes.filter(a => a.classes.split(' ').some(b => b === 'foo'));
console.log(foo);
Upvotes: 5