【问题标题】:Concise way to Group by and Count item in array对数组中的项目进行分组和计数的简洁方法
【发布时间】:2021-06-27 08:04:50
【问题描述】:

我有一个这样的数组:

const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, 
              {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, 
              {name: 'Server 5', country: 'US'}];

我想要的是group and count 得到如下输出:

 [
  {
    "country": "DE",
    "count": 2
  },
  {
    "country": "PL",
    "count": 1
  },
  {
    "country": "US",
    "count": 2
  }
]

目前,我正在使用lodash,但我认为有更好的方法(例如,使用_groupBy 或类似的东西) 来解决它,对吧?

我的代码在这里:

const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];

const objectGroupby = _.countBy(arr, 'country');
const result = Object.entries(objectGroupby).map(([key, value]) => ({country: key, count: value}));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

如您所见,_.countBy(arr, 'country') 只是返回一个对象而不是数组。

{
  "DE": 2,
  "PL": 1,
  "US": 2
}

那我得用Object.entries()&map来解决。

【问题讨论】:

    标签: javascript group-by count lodash


    【解决方案1】:

    在性能方面,我认为我可以使用简单的for loops as for loops are faster than .map(), .reduce() 等编写性能更高的代码。

    遍历原数组一次,可以做到以下几点,

    const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
    
    let mapObj = {};
    let res = [];
    let resIndex = 0;
    
    for(let i = 0; i < arr.length; i++) {
      if(mapObj[arr[i].country] >= 0) {
        res[mapObj[arr[i].country]].count++;
      } else {
        res.push({country: arr[i].country, count: 1});
        mapObj[arr[i].country] = resIndex;
        resIndex++;
      }
    }
    
    console.log(res);

    就优雅或更易读的代码而言,我认为使用reduce 更易读。但可读性是主观的,因人而异。对我来说,reduce 会更具可读性。

    const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
    
    res = arr.reduce((prev, curr) => {
      const index = prev.findIndex(item => item.country === curr.country);
      if(index > -1) {
        prev[index].count++;
      } else {
        prev.push({ country: curr.country, count: 1});
      }
      return prev;
    }, []);
    
    console.log(res);

    更新: 使用 Lodash,

    const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
    
    result = _.reduce(_.countBy(arr, 'country'), (result, value, key) => {
      result.push({ country: key, count: value});
      return result;
    }, []);
    
    console.log(result);
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 感谢您的回答。但我想到了除_.countBy 之外的另一个lodash's method。无论如何 +1 尊重。
    • 嗨,我已经更新了我的答案。我认为 'lodash' 中的 _.reduce() 可以用来编写更紧凑和可读的代码。请看一看。
    • 是的,看起来不错。就个人而言,在这种情况下使用Array#reduce 是最简洁的。谢谢。
    • 在性能方面,你觉得Object.entries() + map_.countBy(arr, 'country')之间的_.reduce之间怎么样?我的意思是 Object.entries 实际上是做什么的?
    • 根据我的观察,Object.entries() 需要一次迭代,然后您使用 map 进行另一次迭代。但是对于`_.reduce()`,您只使用了一次迭代。这取决于 JS 引擎的实现。但大致它会遍历你的对象并返回一个数组。你可以在这里看到developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
    【解决方案2】:

    万岁!!!

    经过最近几天的研究,我终于想出了像这样使用groupBy的解决方案。

    const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
    const result = _(arr).groupBy(x => x.country)
                         .map((value, key) => ({country: key, count: value.length})); 
    console.log(result);
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"&gt;&lt;/script&gt;

    说明:

    1. 第一步:根据country属性对数组元素进行分组
    2. 第 2 步:使用具有 2 个参数值的 .map:key 是组的名称(国家/地区),value 是对象数组。

    参考资源:

    【讨论】:

      猜你喜欢
      • 2023-02-16
      • 1970-01-01
      • 2011-06-13
      • 2020-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-07
      相关资源
      最近更新 更多