Home > Mobile >  How to use reduce, map, or filter to create a function to display and count each values of array obj
How to use reduce, map, or filter to create a function to display and count each values of array obj

Time:06-13

How can I create a function that will return the number of each breed?

const dogs = [
    {
        name:"Cherry",
        breed:["Shiba", "Poodle"]
    },
    {
        name:"Bolt",
        breed:["Shiba"]
    },
    {
        name:"Pumpkin",
        breed:["Chihuahua", "Poodle"]
    },
    {
        name:"Happy",
        breed:["Poodle"]
    },
    {
        name:"Tofu",
        breed:["German Shepherd"]
    }
];

I want to print each breeds and its count like below.

{
German Shepherd: 1,
Shiba: 2,
Poodle: 3,
Chihuahua:1
}

Edit: Also how can I pass a specific breed as an argument and print only that breed and its count?

I started understanding some concepts and functions but it is still challenging for me to combine multiple different concepts.

CodePudding user response:

You can use reduce and repeat that on the nested arrays:

const dogs = [{name:"Cherry",breed:["Shiba", "Poodle"]},{name:"Bolt",breed:["Shiba"]},{name:"Pumpkin",breed:["Chihuahua", "Poodle"]},{name:"Happy",breed:["Poodle"]}, {name:"Tofu",breed:["German Shepherd"]}];

const result = dogs.reduce((acc, {breed}) => 
    breed.reduce((acc, name) => {
        acc[name] = (acc[name] ?? 0)   1;
        return acc;
    }, acc)
, {});

console.log(result);

Alternatively, you could first flatten the data into an array of strings, and then reduce that:

const dogs = [{name:"Cherry",breed:["Shiba", "Poodle"]},{name:"Bolt",breed:["Shiba"]},{name:"Pumpkin",breed:["Chihuahua", "Poodle"]},{name:"Happy",breed:["Poodle"]}, {name:"Tofu",breed:["German Shepherd"]}];

const result = dogs.flatMap(({breed}) => breed).reduce((acc, name) => {
    acc[name] = (acc[name] ?? 0)   1;
    return acc;
}, {});

console.log(result);

CodePudding user response:

There's no real need for reduce, filter, or map here.

  1. Create an object to group the scores by breed.
  2. Iterate over the dogs array, then iterate over the breeds array for each dog. If the breed doesn't already exist on the object create it and set the value to zero.
  3. Add one to the breed value.

In answer to your comment about passing in a separate breed argument to just get the totals for that breed, just amend the function a little.

const dogs=[{name:"Cherry",breed:["Shiba","Poodle"]},{name:"Bolt",breed:["Shiba"]},{name:"Pumpkin",breed:["Chihuahua","Poodle"]},{name:"Happy",breed:["Poodle"]},{name:"Tofu",breed:["German Shepherd"]}];

// Pass in the dogs array
// and an optional query string
function getBreedCount(dogs, query) {

  // Grouping object
  const obj = {};

  // Iterate over the dogs, and the breeds
  // updating the grouping object as we go
  for (const dog of dogs) {
    for (breed of dog.breed) {
      obj[breed] ??= 0;
        obj[breed];
    }
  }

  // If there is a query argument...
  if (query) {

    // ...and the query string is a key on the object
    // Return a string: `<breed>: <value>`...
    if (obj[query]) return `${query}: ${obj[query]}`;

    // ...otherwise return a message that
    // the breed doesn't exist
    return `${query} doesn't exist`;

  }

  // If there is no query argument
  // return the complete object
  return obj;

}

console.log(getBreedCount(dogs));
console.log(getBreedCount(dogs, 'Poodle'));
console.log(getBreedCount(dogs, 'Shiba'));
console.log(getBreedCount(dogs, 'Bobby Davro'));

Additional documentation

CodePudding user response:

You can do this. First, Extract the key you want with map (breed).

function getBreed (dog) {
  return dog.breed;
}

console.log(dogs.map(getBreed))
// [Array(2), Array(1), Array(2), Array(1), Array(1)]

You can also simplify this with the arrow function

const breeds = dogs.map(dog => dog.breed)
console.log(breeds)
// The same output
// [Array(2), Array(1), Array(2), Array(1), Array(1)]

Then you can merge all arrays into a one-dimensional array with reduce and concat.

const flatten = breeds.reduce((arr, breed) => arr.concat(breed), [])
console.log(flatten)
// ['Shiba', 'Poodle', 'Shiba', 'Chihuahua', 'Poodle', 'Poodle', 'German Shepherd']

Finally, You can count items with reduce

function count(counter, breed) {
    if (breed in counter)
        counter[breed]  ;
    else
        counter[breed] = 1;
    return counter
}
console.log(flatten.reduce(count, {}))
// {Shiba: 2, Poodle: 3, Chihuahua: 1, German Shepherd: 1}

If you wondering what happened here you can see the documentation but in short, ‍The counter is an empty object ‍‍{} in the first. Then in step 1 it becomes to {Shiba:1} because Sheba wasn't in the counter. In step 2 it becomes {Shiba:1,Poodle:1} for the same reason. In step 3 Sheba Increases and counter becomes {Shiba:2,Poodle:1} because Sheba exists in counter before and etc.

  • Related