Mazzy
Mazzy

Reputation: 14189

Remove properties from the object with value equal to zero

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

Answers (3)

T.J. Crowder
T.J. Crowder

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

Mulan
Mulan

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

Mazzy
Mazzy

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

Related Questions