Home > OS >  can we use reduce function as a map function?
can we use reduce function as a map function?

Time:08-27

I have an array of objects, where I want to count the occurrences of the country, the list is given below:

let userData =  [
      {
        "id": 1,
        "fullName": "ABC",
        "title": "ABC",
        "designation": "ABC",
        "email": "ABC",
        "companyName":"ABC",
        "country": "Pakistan",
        "officeTel": "92#12344",
        "mobileNumber": "1234134",
        "password": "123456",
        "companyIntro": null,
        "businessSector": "Test",
        "previousInvestment": null,
        "plannedInvestment": null,
        "webAddress": null,
        "status": "Active",
        "reason": null,
        "businessSectorOthers": null
      },
    ]

by using reduce method I am able to count the occurrences if the country present in the list. The Result is:

[
  Afghanistan: 5
  Albania: 1
  Andorra: 5
  Austria: 1
  Central African Republic: 1
  Pakistan: 16
  United Kingdom: 1
  turkey: 1
],

But I want the result to be an array of objects containing properties of countryName and count and it should be like this:

[
   {
     countryName: "Pakistan",
     count: 16
   },
   {
     countryName: "Austria",
     count: 1
   }
]

Here is my code for counting the occurences:

userData?.reduce((prevVal, currVal) => {
            prevVal[currVal.country] = (prevVal[currVal.country] || 0)   1;

            return prevVal;
          }, []);

CodePudding user response:

You can do it like this:

const result = data.reduce(
    (countriesCount, item) => {
        let countryCount = countriesCount.find(
            (countryCount) => countryCount.countryName === item.country
        );
        if (!countryCount) {
            countryCount = {
                countryName: item.country,
                count: 0,
            };
            countriesCount.push(countryCount);
        }
          countryCount.count;
        return countriesCount;
    },
    []
);

But it would transverse the array several times. It's not efficient. It's better to use a map:

const result = Array.from(
    data.reduce(
        (countriesCount, item) => {
            let countryCount = countriesCount.get(item.country);
            if (!countryCount) {
                countryCount = {
                    countryName: item.country,
                    count: 0
                };
                countriesCount.set(item.country, countryCount);
            }
              countryCount.count;
            return countriesCount;
        },
        new Map()
    ).values()
);

Or an object:

const result = Object.values(
    data.reduce(
        (countriesCount, item) => {
            if (!countriesCount[item.country]) {
                countriesCount[item.country] = {
                    countryName: item.country,
                    count: 0
                };
            }
              countriesCount[item.country].count;
            return countriesCount;
        },
        {}
    )
);

Added suggestion

I believe you should not force yourself using a tool to solve a problem. Unless it's just an exercise, to check how it is possible and learn about it. Check the advantages and disadvantages. What reduce means? Will it make the code more readable? Or more efficient? Or more scalable? What is more important in the context of the problem or project?

According to the documentation, in MDN:

The reduce() method executes a user-supplied "reducer" callback function on each element of the array, in order, passing in the return value from the calculation on the preceding element. The final result of running the reducer across all elements of the array is a single value.

Though you can use reduce to return an array of objects, maybe the usage of that method is not conveying that idea. Thus, it's helping the readability. Especially if it requires writing more than other methods. Also, it's not more efficient than using a for loop or a forEach.

You can do, for example, this instead:

const countriesCount = {};
data.forEach(item => {
    countriesCount[item.country] = 1   (countriesCount[item.country] ?? 0);
});
const result = Object.entries(countriesCount).map(
    ([country, number]) => (
        {
            countryName: country,
            count: number
        }
    )
);

CodePudding user response:

This should work

    const countries = [
    {
        "country": "Pakistan",
    },
    {
        "country": "Pakistan",
    },
    {
        "country": "Pakistan",
    },
    {
        "country": "Test",
    },
    {
        "country": "Pakistan",
    },
]

    const countriesWithCount = []
    
    countries.forEach(item => {
        const index = countriesWithCount.findIndex(({ country }) => item.country === country)
        index >= 0 ? countriesWithCount[index].count   : countriesWithCount.push({ country: item.country, count: 1 })
    })

CodePudding user response:

is this what you want?

const countries = [
    {
        "country": "Pakistan",
    },
    {
        "country": "Pakistan",
    },
    {
        "country": "Pakistan",
    },
    {
        "country": "Test",
    },
    {
        "country": "Pakistan",
    },
]

const result = countries.reduce((prevVal,currVal)=>{
  let existedCountry = prevVal?.find(o => o.countriyName === currVal.country)
  if(existedCountry) {
    existedCountry.count   
    return prevVal
  }
  return [...prevVal,{countriyName :currVal.country,count:1}]
},[])

console.log(result)

  • Related