【问题标题】:Summarize count of occurrences in an array of objects with Array#reduce使用 Array#reduce 汇总对象数组中出现的次数
【发布时间】:2016-12-22 00:07:26
【问题描述】:

我想汇总一个对象数组并返回另一个对象数组中对象出现的次数。最好的方法是什么?

从此

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

【问题讨论】:

  • "我正在尝试..." – 你尝试了什么?你走了多远?怎么了?它是怎么出错的?
  • Object -> 数组很容易使用 Object.keys 和 Array#map ... 例如Object.keys(obj).map(title => ({title, playCount:obj[title]}));
  • 将该对象更改为您想要的数组应该很简单,只需遍历属性即可。

标签: javascript arrays javascript-objects


【解决方案1】:

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

工作sn-p

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

【讨论】:

    【解决方案2】:

    要在您已经完成的基础上再接再厉,下一步是将对象“转换”为数组

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

    【讨论】:

      【解决方案3】:

      我建议分两个阶段执行此操作。首先,按标题对数组进行分块,然后将这些块映射到您想要的输出中。这将真正帮助你在未来的变化。一次性完成这一切非常复杂,并且会增加将来搞砸的机会。

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

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

      【讨论】:

        【解决方案4】:

        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/

        【讨论】:

        • 你为什么要使用arrayOfSongs.map 两次,而arrayOfSongs.forEach 会更合适,因为你不使用.map 返回值?为什么你的结果是一个对象,而不是一个数组!!!
        猜你喜欢
        • 1970-01-01
        • 2019-10-28
        • 2020-01-07
        • 2019-02-27
        • 2016-09-30
        • 1970-01-01
        • 2019-09-24
        • 1970-01-01
        • 2021-07-05
        相关资源
        最近更新 更多