Reputation: 14189
removeZero({ a: 0, b: 1, c: -1 })
output:
removeZero({ b: 1, c: -1 })
I'm trying to write a function in the functional programming approach which use just map()
, reduce()
, filter()
. this was my best approach but it didn't work.
const removeZero = (item) => (
Object
.keys(item)
.filter(Boolean)
.map((key) => ({ [key]: item[key] }))
.reduce((acc, curr) => ({ ...acc, ...curr }))
)
Any idea how to fix this?
Upvotes: 1
Views: 1364
Reputation: 1074238
You're pretty close. This works and is mostly functional (I think; I'm not at all steeped in the idioms of functional programming), but barring using Object.defineProperty
to define the properties I think you're going to have to go imperative for the last step (setting the props):
const removeZero = item => (
Object
.keys(item)
.filter(key => item[key] !== 0)
.reduce((newObj, key) => {
newObj[key] = item[key];
return newObj;
}, {})
);
const result = removeZero({ a: 0, b: 1, c: -1 });
console.log(result);
I suppose we could create a new object every time in the reduce
, but it seems wasteful:
const removeZero = item => (
Object
.keys(item)
.filter(key => item[key] !== 0)
.reduce((newObj, key) => ({
...newObj, [key]: item[key]
}), {})
);
const result = removeZero({ a: 0, b: 1, c: -1 });
console.log(result);
...but note that that relies on object spread notation, which is a Stage 3 proposal (and likely to be in ES2018) but is not in the spec yet.
naomik points out that we can avoid doing the
newObj[key] = item[key];
return newObj;
part without creating a new object by using Object.assign
, like this:
const removeZero = item => (
Object
.keys(item)
.filter(key => item[key] !== 0)
.reduce((newObj, key) => Object.assign(newObj, {[key]: item[key]}), {})
);
const result = removeZero({ a: 0, b: 1, c: -1 });
console.log(result);
I'll leave it to more functional heads than mine whether that's more functional than the one setting the property and doing return
. :-)
Upvotes: 3
Reputation: 135217
Well you don't need the intermediate .filter
or .map
step. They read a bit nicer but add lots of unnecessary iteration in the process. You could write your function as a single reduce
const removeZero = o =>
Object.keys(o)
.reduce((acc, k) => {
if (o[k] === 0)
return acc
else
return Object.assign(acc, { [k]: o[k] })
}, {})
let output = removeZero({ a: 0, b: 1, c: -1 })
console.log(output)
Or if you like @TJCrowder's approach but want to dodge the imperative assignment or spread object proposal, you can use an Object.assign
expression
const removeZero = o =>
Object.keys(o)
.filter(k => o[k] !== 0)
.reduce((acc, k) =>
Object.assign(acc, { [k]: o[k] }), {})
let output = removeZero({ a: 0, b: 1, c: -1 })
console.log(output)
Upvotes: 1
Reputation: 14189
thanks to T.J I've arrived to this solution:
const setProp = (item, key) => ({[key]: item[key]})
const removeZero = (item) => (
Object
.keys(item)
.filter((key) => item[key])
.reduce((acc, curr) => ({ ...acc, ...setProp(item, curr) }), {})
)
Upvotes: 0