Home > Software engineering >  alternative to multiple .forEach() loops for filter in Javascript
alternative to multiple .forEach() loops for filter in Javascript

Time:12-05

There is a use case to filter key/value pairs that have a value of zero out of the following dataset. If all the values are zero for the given key then the key/value pair is to be filtered out entirely (as is the case for keys 41521, 41530).

    const simpleData = {
        "41511": {
            "count": 0,
            "probability": 0.000017
        },
        "41521": {
            "count": 0,
            "probability": 0
        },
        "41530": {
            "count": 0,
            "probability": 0
        },
        "41540": {
            "count": 0,
            "probability": 0.000085
        },
        "41551": {
            "count": 1,
            "probability": 1
        }
    };

    acc = {};

    Object.entries(simpleData).forEach(([key, value]) => {
        acc[key] = {};
        Object.entries(value).forEach(([k, v]) => {
            if (v !== 0) acc[key][k] = v;
        });
        if (Object.keys(acc[key]).length === 0) delete acc[key];
    });

    // console.log('simpleData', simpleData);
    console.log('acc ', acc);

The current approach uses two .forEach() loops. Is there a different way to do this filtering that avoids multiple .forEach() loops?

CodePudding user response:

Yes, there is another way to achieve the same result that avoids using multiple forEach() loops. Instead of using two forEach() loops, you can use a combination of filter() and map() to filter out the key/value pairs that have a value of zero.

Here's an example of how this can be done:

const simpleData = {
    "41511": {
        "count": 0,
        "probability": 0.000017
    },
    "41521": {
        "count": 0,
        "probability": 0
    },
    "41530": {
        "count": 0,
        "probability": 0
    },
    "41540": {
        "count": 0,
        "probability": 0.000085
    },
    "41551": {
        "count": 1,
        "probability": 1
    }
};

// Filter out the key/value pairs that have a value of zero
const filteredData = Object.entries(simpleData)
    .filter(([key, value]) => {
        // Check if all the values in the object are zero
        return Object.values(value).every(v => v !== 0);
    })
    .map(([key, value]) => {
        // Return the key/value pair as a new object
        return { [key]: value };
    });

console.log(filteredData);

In this example, we first use Object.entries() to convert the simpleData object into an array of key/value pairs. We then use filter() to remove any key/value pairs that have a value of zero. Finally, we use map() to convert the remaining key/value pairs back into objects.

CodePudding user response:

Actually multiple loops are not need as you can achieve your goal using the filter method to filter out the items where the count and probability keys equal to 0 or in other words to keep the items that have at least one key from count and probability keys that is not 0.

Here's a live demo:

const simpleData = {
    "41511": {
      "count": 0,
      "probability": 0.000017
    },
    "41521": {
      "count": 0,
      "probability": 0
    },
    "41530": {
      "count": 0,
      "probability": 0
    },
    "41540": {
      "count": 0,
      "probability": 0.000085
    },
    "41551": {
      "count": 1,
      "probability": 1
    }
  },
  /**
   * filtered array will contain the filtered data.
   * we'll only keep the items where at least one of the keys ("count" or "probability") is not equal to "0"
   */
  filtered = Object.entries(simpleData).filter(([k, v]) => v['count'] > 0 || v['probability'] > 0);

// print the result
console.log(filtered);

The above method prevents you from having multiple loops but now the filtered array no longer contain object but rather each item will be an array where the key 0 is the key from the original object (like 41511 and the key 1 is the actual data (like {"count": 0, "probability": 0.000017}.

CodePudding user response:

const simpleData = {
    "41511": {
        "count": 0,
        "probability": 0.000017
    },
    "41521": {
        "count": 0,
        "probability": 0
    },
    "41530": {
        "count": 0,
        "probability": 0
    },
    "41540": {
        "count": 0,
        "probability": 0.000085
    },
    "41551": {
        "count": 1,
        "probability": 1
    }
};

acc = {};
Object.entries(simpleData).forEach(([key, value]) => {
    tmp = Object.entries(value).filter(([, v]) => v !== 0);
    if (tmp.length !== 0) acc[key] = Object.fromEntries(tmp);
});
console.log('acc ', acc);

CodePudding user response:

const finalResult = Object.entries(simpleData)
  .filter(([eachKey, eachValue]) => {
    if (!eachValue["count"] && !eachValue["probability"]) return false;
    return true;
  })
  .map(([eachKey, eachValue]) => {
    if (eachValue["count"] && eachValue["probability"]) {
      return {
        [eachKey]: eachValue,
      };
    }
    if (!eachValue["count"]) {
      return {
        [eachKey]: {
          probability: eachValue["probability"],
        },
      };
    }

    if (!eachValue["probability"]) {
      return {
        [eachKey]: {
          count: eachValue["count"],
        },
      };
    }
  })
  .reduce((prev, current) => {
    return {
      ...prev,
      ...current,
    };
  });

console.log("finalResult is", finalResult);

  • Related