0

Is there a more efficient way to achieve this? My desired output is to create a new array out of the following object. If supported === true, add id to array. So in below object, the output should be ['CREDIT', 'DEBIT'].

 const object = {
   "cardOptions": [
   {
      "id": "CREDIT",
      "supported": true
   },
   {
      "id": "DEBIT",
      "supported": true
   }
  ]
 }

Here is what I have now.

 const cardTypes = object.reduce((filtered, cardType) => {
      if (cardType.id && cardType.supportedAtLocation) {
          filtered.push(cardType.id)
      }
      return filtered
 }, [])
4
  • What is inefficient about this solution? Commented Aug 4, 2020 at 4:03
  • I'm wondering if reduce is the best method. Or if using map or filter is possible and better. Commented Aug 4, 2020 at 4:04
  • Reduce is the appropriate choice, cos you're filtering the array and creating a new data structure out of it. If you use @g2jose's method, it would work but then you're looping over the array twice. Reduce allows for one pass Commented Aug 4, 2020 at 4:09
  • You need object.cardOptions.reduce instead of object.reduce but that works. I'd personally go for filter + map but it is technically less optimal. Depending on your data, that might not matter, though and if you use something that allows lazy evaluation like Lodash, then you can change object.cardOptions.filter().map() with _(object.cardOptions).filter().map() and you'd avoid the double iteration. Ultimately, though Eric Lippert said it best - what is better and if it atters depends on circumstances. Commented Aug 4, 2020 at 4:09

1 Answer 1

2

You can also use filter + map like this:

object.cardOptions
  .filter(option => option.supported)
  .map(cardOption => cardOption.id)

Profiling this side by side using the User Timing API, at least on chrome, it seems like your reduce code is more efficient (but practically it probably won't matter unless you have a really large dataset).

Here's a quick higher order profiling function I often use:

// A function to run an input function several times and profile performance using the User Timing API on chrome
const profile = (func, times) => (...args) => {
    const functionName = func.name;
    const trackName = `${functionName}`;
    const startTag = `${trackName}_start`;
    window.performance.mark(startTag);
    let results;
    for (let i = 0; i < times; i = i + 1)
        results = func(...args);
    const endTag = `${trackName}_end`;
    window.performance.mark(endTag);
    window.performance.measure(trackName, startTag, endTag);
    return results;
};
const object = {
    cardOptions: [
        {
            id: 'CREDIT',
            supported: true,
        },
        {
            id: 'DEBIT',
            supported: true,
        },
    ],
};
const filterMap = () => {
    object.cardOptions
        .filter(option => option.supported)
        .map(cardOption => cardOption.id);
};
const reduce = () => {
    object.cardOptions.reduce((filtered, cardType) => {
        if (cardType.id && cardType.supported) {
            filtered.push(cardType.id);
        }
        return filtered;
    }, []);
};

profile(filterMap, 99999)();
profile(reduce, 99999)();

The output of the measure looks like so:

window.performance.getEntriesByType('measure')

[
  {
    name: 'profileFilterMap',
    entryType: 'measure',
    startTime: 310637.6400000008,
    duration: 30.029999994440004, // higher duration for map + filter
  },
  {
    name: 'profileReduce',
    entryType: 'measure',
    startTime: 310667.7550000022,
    duration: 24.754999991273507, // reduce seems slightly more efficient
  },
]

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.