使用Array#reduce汇总对象数组中的出现次数

时间:2016-12-22 00:07:27

标签: javascript arrays javascript-objects

我想总结一个对象数组,并在另一个对象数组中返回对象出现次数。这样做的最佳方式是什么?

来自此

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 = [
  {"title": "Blue", "playCount": 3 },
  {"title": "Green", "playCount": 1}
]

我试过

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

但它返回一个对象:

 { "Blue": 3, "Green": 1};

4 个答案:

答案 0 :(得分:1)

您应该将初始参数作为数组传递给reduce函数而不是现有值的对象和过滤器数组,如下所示,

工作代码

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);

答案 1 :(得分:1)

要建立你已经完成的工作,下一步是将对象“转换”为数组

NULL

答案 2 :(得分:1)

我建议分两个阶段进行。首先,按标题对数组进行分块,然后将块映射到您想要的输出中。这将真正帮助您在未来的变化。一次性完成这一过程非常复杂,并且将增加将来搞乱的可能性。

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"}
];

function chunkByAttribute(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
  };
});

在那里,现在一切都根据它的作用命名,一切都只做一件事,并且更容易理解。

答案 3 :(得分:0)

https://jsfiddle.net/93e35wcq/

我使用set对象来获取唯一的曲目标题,然后使用Array.map拼接它们并返回包含曲目标题内的播放计数的歌曲对象。

数据:

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"
}];

功能:

function getPlayCount(arrayOfSongs) {
  let songObj = {};
  let SongSet = new Set();
  arrayOfSongs.map(obj => (SongSet.has(obj.title)) ? true : SongSet.add(obj.title));
  for (let songTitle of SongSet.values()) {
    songObj[songTitle] = {
      playCount: 0
    };
    arrayOfSongs.map(obj => (obj.title === songTitle) ? songObj[songTitle].playCount++ : false)
  }
  return songObj;
}

console.log(getPlayCount(arrayOfSongs));

这并不是你想要格式化的东西,但是如果你嫁给了它,这就行了:

    function getPlayCount(arrayOfSongs) {
  let songObj = {};
  let SongSet = new Set();
  arrayOfSongs.map(obj => (SongSet.has(obj.title)) ? true : SongSet.add(obj.title));
  for (let songTitle of SongSet.values()) {
    songObj[songTitle] = 0;
    arrayOfSongs.map(obj => (obj.title === songTitle) ? songObj[songTitle]++ : false)
  }
  return songObj;
}

console.log(getPlayCount(arrayOfSongs));

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