Skip to content Skip to sidebar Skip to footer

Summarize Count Of Occurrences In An Array Of Objects With Array#reduce

I want to summarize an array of objects and return the number of object occurrences in another array of objects. What is the best way to do this? From this var arrayOfSongs = [ {

Solution 1:

You should pass the initial argument to the reduce function as an array instead of object and filter array for the existing value as below,

Working snippet:

var arrayOfSongs = [
  {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
  {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
  {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
  {"title":"Green","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"}
];


var newArrayOfSongs = arrayOfSongs.reduce(function(acc, cv) {
    var arr = acc.filter(function(obj) {
      return obj.title === cv.title;
    });
   
    if(arr.length === 0) {
      acc.push({title: cv.title, playCount: 1});
    } else {
      arr[0].playCount += 1;
    }
    
    return acc;
   }, []);

console.log(newArrayOfSongs);

Solution 2:

To build on what you already have done, the next step is to "convert" the object to an array

var arrayOfSongs = [
        {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
        {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
        {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
        {"title":"Green","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"}
    ];

    var obj = arrayOfSongs.reduce(function(acc, cv) {
       acc[cv.title] = (acc[cv.title] || 0) + 1;
       return acc;
    }, {});

    // *** added code starts here ***var newArrayOfSongs = Object.keys(obj).map(function(title) { 
        return {
            title: title, 
            playCount:obj[title]
        };
    });

    console.log(newArrayOfSongs);

Solution 3:

I recommend doing this in two stages. First, chunk the array by title, then map the chunks into the output you want. This will really help you in future changes. Doing this all in one pass is highly complex and will increase the chance of messing up in the future.

var arrayOfSongs = [
  {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
  {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
  {"title":"Blue","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"},
  {"title":"Green","duration":161.71,"audioUrl":"/assets/music/blue","playing":false,"playedAt":"2016-12-21T22:58:55.203Z"}
];

functionchunkByAttribute(arr, attr) {
  return arr.reduce(function(acc, e) {
   acc[e[attr]] = acc[e[attr]] || [];
   acc[e[attr]].push(e);
   return acc;
  }, {});
}

var songsByTitle = chunkByAttribute(arrayOfSongs, 'title');

var formattedOutput = Object.keys(songsByTitle).map(function (title) {
  return {
    title: title,
    playCount: songsByTitle[title].length
  };
});

There, now everything is named according to what it does, everything does just one thing, and is a bit easier to follow.

Solution 4:

https://jsfiddle.net/93e35wcq/

I used a set object to get the unique track titles, then used Array.map to splice those and return a song object that contains play count inside the track title.

The Data:

var arrayOfSongs = [{
  "title": "Blue",
  "duration": 161.71,
  "audioUrl": "/assets/music/blue",
  "playing": false,
  "playedAt": "2016-12-21T22:58:55.203Z"
}, {
  "title": "Blue",
  "duration": 161.71,
  "audioUrl": "/assets/music/blue",
  "playing": false,
  "playedAt": "2016-12-21T22:58:55.203Z"
}, {
  "title": "Blue",
  "duration": 161.71,
  "audioUrl": "/assets/music/blue",
  "playing": false,
  "playedAt": "2016-12-21T22:58:55.203Z"
}, {
  "title": "Green",
  "duration": 161.71,
  "audioUrl": "/assets/music/blue",
  "playing": false,
  "playedAt": "2016-12-21T22:58:55.203Z"
}];

The Function:

functiongetPlayCount(arrayOfSongs) {
  let songObj = {};
  letSongSet = newSet();
  arrayOfSongs.map(obj => (SongSet.has(obj.title)) ? true : SongSet.add(obj.title));
  for (let songTitle ofSongSet.values()) {
    songObj[songTitle] = {
      playCount: 0
    };
    arrayOfSongs.map(obj => (obj.title === songTitle) ? songObj[songTitle].playCount++ : false)
  }
  return songObj;
}

console.log(getPlayCount(arrayOfSongs));

Which isn't exactly what you wanted formatting wise, but if you're married to it, this will do the trick:

functiongetPlayCount(arrayOfSongs) {
  let songObj = {};
  letSongSet = newSet();
  arrayOfSongs.map(obj => (SongSet.has(obj.title)) ? true : SongSet.add(obj.title));
  for (let songTitle ofSongSet.values()) {
    songObj[songTitle] = 0;
    arrayOfSongs.map(obj => (obj.title === songTitle) ? songObj[songTitle]++ : false)
  }
  return songObj;
}

console.log(getPlayCount(arrayOfSongs));

https://jsfiddle.net/93e35wcq/1/

Post a Comment for "Summarize Count Of Occurrences In An Array Of Objects With Array#reduce"