Use reduce and add another value to the result object

Viewed 410

Example of an object in the books array:

const books = [
  {
    id: "5f447132d487bd81da01e25e",
    title: "sit eiusmod occaecat eu magna",
    genre: "Science",
    authorId: 8,
    borrows: [
      {
        id: "5f446f2e2cfa3e1d234679b9",
        returned: false,
      },
      {
        id: "5f446f2ed3609b719568a415",
        returned: true,
      },
      {
        id: "5f446f2e1c71888e2233621e",
        returned: true,
      },
      {
        id: "5f446f2e6059326d9feb9a68",
        returned: true,
      },
      {
        id: "5f446f2ede05a0b1e3394d8b",
        returned: true,
      },
      {
        id: "5f446f2e4081699cdc6a2735",
        returned: true,
      },
      {
        id: "5f446f2e3900dfec59489477",
        returned: true,
      },
      {
        id: "5f446f2e6059326d9feb9a68",
        returned: true,
      },
      {
        id: "5f446f2e409f8883af2955dd",
        returned: true,
      },
      {
        id: "5f446f2e3900dfec59489477",
        returned: true,
      },
      {
        id: "5f446f2eae901a82e0259947",
        returned: true,
      },
      {
        id: "5f446f2ef2ab5f5a9f60c4f2",
        returned: true,
      },
      {
        id: "5f446f2ea6b68cf6f85f6e28",
        returned: true,
      },
      {
        id: "5f446f2eed18105706d6ca19",
        returned: true,
      },
      {
        id: "5f446f2eae901a82e0259947",
        returned: true,
      },
      {
        id: "5f446f2e91c2af00cb74e82b",
        returned: true,
      },
      {
        id: "5f446f2e5aa2bb5545a0f8a6",
        returned: true,
      },
      {
        id: "5f446f2ea508b6a99c3e42c6",
        returned: true,
      },
      {
        id: "5f446f2e50cc2da9cd80efdb",
        returned: true,
      },
      {
        id: "5f446f2e0b3e2ff72fc503e7",
        returned: true,
      },
      {
        id: "5f446f2e91c2af00cb74e82b",
        returned: true,
      },
      {
        id: "5f446f2ef795e593cd3cd19d",
        returned: true,
      },
      {
        id: "5f446f2e2f35653fa80bf490",
        returned: true,
      },
      {
        id: "5f446f2e7b9cd304fed3a8bc",
        returned: true,
      },
      {
        id: "5f446f2ed9aac23c0340aab2",
        returned: true,
      },
    ],
  },

I need my function getMostCommonGenres(books) to: return an array containing five objects or fewer that represents the most common occurring genres, ordered from most common to least, like so: (If more than five books are present, only the top five should be returned.)

getMostCommonGenres(books);
  [
    { name: "Nonfiction", count: 9 },
    { name: "Historical Fiction", count: 7 },
    { name: "Thriller", count: 7 },
    ...
  ]

This is what I have so far:

function getMostCommonGenres(books) {
  const genreArray = books.reduce((acc, book) => {
    acc[book.name] = book.genre;
    return acc;
  }, {});
}

I'm pretty sure I've got what I need to get everything except the 'count' value after the genre. I'm not sure how I would add this to the object. I'm also not sure of how I would stop the count at the top five. I've just finished the advanced functions section in my course so I'm supposed to be using forEach, find, filter, some, every, reduce, or sort. I'm not allowed to use single-letter variables either. Thanks in advance for any assistance.

3 Answers

You can easily achieve this using reduce and slice(to get 5 elements)

const books = [{
  id: "5f447132d487bd81da01e25e",
  title: "sit eiusmod occaecat eu magna",
  genre: "Science",
  authorId: 8,
  borrows: [{
      id: "5f446f2e2cfa3e1d234679b9",
      returned: false,
    },
    {
      id: "5f446f2ed3609b719568a415",
      returned: true,
    },
    {
      id: "5f446f2e1c71888e2233621e",
      returned: true,
    },
    {
      id: "5f446f2e6059326d9feb9a68",
      returned: true,
    },
    {
      id: "5f446f2ede05a0b1e3394d8b",
      returned: true,
    },
    {
      id: "5f446f2e4081699cdc6a2735",
      returned: true,
    },
    {
      id: "5f446f2e3900dfec59489477",
      returned: true,
    },
    {
      id: "5f446f2e6059326d9feb9a68",
      returned: true,
    },
    {
      id: "5f446f2e409f8883af2955dd",
      returned: true,
    },
    {
      id: "5f446f2e3900dfec59489477",
      returned: true,
    },
    {
      id: "5f446f2eae901a82e0259947",
      returned: true,
    },
    {
      id: "5f446f2ef2ab5f5a9f60c4f2",
      returned: true,
    },
    {
      id: "5f446f2ea6b68cf6f85f6e28",
      returned: true,
    },
    {
      id: "5f446f2eed18105706d6ca19",
      returned: true,
    },
    {
      id: "5f446f2eae901a82e0259947",
      returned: true,
    },
    {
      id: "5f446f2e91c2af00cb74e82b",
      returned: true,
    },
    {
      id: "5f446f2e5aa2bb5545a0f8a6",
      returned: true,
    },
    {
      id: "5f446f2ea508b6a99c3e42c6",
      returned: true,
    },
    {
      id: "5f446f2e50cc2da9cd80efdb",
      returned: true,
    },
    {
      id: "5f446f2e0b3e2ff72fc503e7",
      returned: true,
    },
    {
      id: "5f446f2e91c2af00cb74e82b",
      returned: true,
    },
    {
      id: "5f446f2ef795e593cd3cd19d",
      returned: true,
    },
    {
      id: "5f446f2e2f35653fa80bf490",
      returned: true,
    },
    {
      id: "5f446f2e7b9cd304fed3a8bc",
      returned: true,
    },
    {
      id: "5f446f2ed9aac23c0340aab2",
      returned: true,
    },
  ],
}, ];

function getMostCommonGenres(books) {
  const result = books.reduce((acc, book) => {
    if (book.borrows.length > 5) {
      acc.push({
        name: book.genre,
        count: book.borrows.length,
      });
    }
    return acc;
  }, []);
  return result.sort((a, b) => b.count - a.count)
               .slice(0, 5);
}

const resultArray = getMostCommonGenres(books);
console.log(resultArray);

Here is the code I have created to sort your book genres:

function getMostCommonGenres(books) {
    returnStrs = [];
    genres = []; // [["genreName1", 1],["genreName2",1]] The number is the count
    var i;
    for (i = 0; i < books.length; i++) {
        genre = books[i].genre;
        if (!DoesGenreExist(genre, genres)) {
            genres.push([genre, 1]);
        }
    }
    genres.sort(function (a, b) { // Sort genres by the count
        return b[1] - a[1];
    });

    numGenres = genres.length
    if (numGenres > 5) { // take 5 max
        numGenres = 5
    }

    for (i = 0; i < numGenres; i++) {
        var summary = new GenreSummary(genres[i][0], genres[i][1])
        returnStrs.push(JSON.stringify(summary)); // Create genre string and add to return value
    }
    console.log(returnStrs)
    return returnStrs;
}

function DoesGenreExist(genreStr, genres) { // If it exists it also increments the count
    for (i = 0; i < genres.length; i++) {
        if (genres[i][0] == genreStr) {
            genres[i][1]++;
            return true;
        }
    }
    return false;
}

class GenreSummary {
    constructor(name, count) {
        this.name = name;
        this.count = count;
    }
}

I input your book from your first code snippet and got the output below:

[ '{"name":"Science","count":1}' ]

The answers I got didn't seem to work but this worked for me:

function getMostCommonGenres(books) {
  const bookGenres = books.map((book) => book.genre);
  const temp = [];
  //map over book genres
  bookGenres.map((genre) => {
    //for each genre, first check to see if genre already exists in array
    const genreLocation = temp.findIndex((element) => element.name === genre);
    //second, if it exists, increase count by 1
    if (genreLocation >= 0) {
      temp[genreLocation].count = temp[genreLocation].count + 1;
      //else, if it don't exist, push a new genre object onto array with count of 1
    } else {
      temp.push({ name: genre, count: 1 });
    }
  });
  temp.sort((a, b) => b.count - a.count);
  if (temp.length > 5) {
    return temp.slice(0, 5);
  }
  return temp;
}
Related