【问题标题】:Group and count values in an array对数组中的值进行分组和计数
【发布时间】:2017-11-07 07:56:48
【问题描述】:

我有一个包含对象的数组,如下所示。

b = {
  "issues": [{
    "fields": {
      "status": {
        "id": "200",
        "name": "Backlog"
      }
    }
  }, {
    "fields": {
      "status": {
        "id": "202",
        "name": "close"
      }
    }
  }, {
    "fields": {
      "status": {
        "id": "201",
        "name": "close"
      }
    }
  }]
};

我想计算有多少问题的状态为close,有多少问题的状态为backlog。我想将计数保存在一个新数组中,如下所示。

a = [
  {Name: 'Backlog', count: 1},
  {Name: 'close', count: 2}
];

我已经尝试了以下方法。

b.issues.forEach(function(i) {
  var statusName = i.fields.status.name;

  if (statusName in a.Name) {
    a.count = +1;
  } else {
    a.push({
      Name: statusName,
      count: 1
    });
  }
});

但这似乎不起作用。我应该如何实现这个?

【问题讨论】:

  • a.count = + 1; 应该达到什么目的?
  • a的格式是固定的吗?
  • 我猜你的意思是+=
  • no .. a 一开始只是一个空数组。 b 是固定的。

标签: javascript arrays


【解决方案1】:

这样的事情应该可以解决问题。只需遍历您的数据,保留 2 个计数器与每种类型的问题的数量,并最终创建您想要的数据格式。在jsfiddle 上直播。

var b = {
    "issues": [{
        "fields": {
            "status": {
                "id": "200",
                "name": "Backlog"
            }
        }
    }, {
        "fields": {
            "status": {
                "id": "202",
                "name": "close"
            }
        }
    }, {
        "fields": {
            "status": {
                "id": "201",
                "name": "close"
            }
        }
    }]
};

var data = [];
for(var issue of b.issues){
    var entryFound = false;
    var tempObj = {
        name: issue.fields.status.name,
        count: 1
    };

    for(var item of data){
        if(item.name === tempObj.name){
        item.count++;
        entryFound = true;
        break;
      }
    }

    if(!entryFound){
        data.push(tempObj);
    }
}
console.log(data);

【讨论】:

  • 问题是,如果有大约 10 个状态,我将不得不为所有这些状态编写条件。有没有办法获取当前状态并检查数组,就像我尝试做的那样.. ?
  • @Y.Hewa 检查我更新的答案。这应该涵盖您的情况。您可以迭代您的输入,如果您发现它已经在您的列表中,只需将其数量增加一,如果不是简单地将其作为新项目推送到您的数据数组。
【解决方案2】:

这是使用Array#reduce 的绝佳机会。该函数将采用一个按顺序应用于数组所有元素的函数,并可用于累积一个值。我们可以使用它来累积一个包含各种计数的对象。

为简单起见,我们将对象中的计数简单地跟踪为{name: count, otherName: otherCount}。对于每个元素,我们检查是否已经有name 的条目。如果没有,请创建一个计数0。否则,增加计数。在reduce 之后,我们可以将map 存储为keys of the object 的键数组采用问题中描述的格式。见下文。

var b = {
  "issues": [{
    "fields": {
      "status": {
        "id": "200",
        "name": "Backlog"
      }
    }
  }, {
    "fields": {
      "status": {
        "id": "202",
        "name": "close"
      }
    }
  }, {
    "fields": {
      "status": {
        "id": "201",
        "name": "close"
      }
    }
  }]
};

var counts = b.issues.reduce((p, c) => {
  var name = c.fields.status.name;
  if (!p.hasOwnProperty(name)) {
    p[name] = 0;
  }
  p[name]++;
  return p;
}, {});

console.log(counts);

var countsExtended = Object.keys(counts).map(k => {
  return {name: k, count: counts[k]}; });

console.log(countsExtended);
.as-console-wrapper {
  max-height: 100% !important;
}

备注。

  1. Array#reduce 不会修改原始数组。
  2. 您可以轻松修改传递给 reduce 的函数,例如通过更改不区分 Backlogbacklog

    var name = c.fields.status.name;
    

    进入

    var name = c.fields.status.name.toLowerCase();
    

    例如。更高级的功能也可以轻松实现。

【讨论】:

  • 这会改变原始数组吗?我希望结果与原始数组不同..
  • 这正是 reduce 的用途。不,它不会改变原始数组。
  • 我试过你的代码..(我已经更新了我的代码)但它说 counts.map 不是一个函数。注意:我确实改变了一些东西..比如删除对象键功能并改变箭头功能..你能检查一下吗..
  • 您的问题是删除了Object.keyscounts 存储在一个对象中,而 map 是为数组定义的。我们将对象的键(遇到的所有名称)放在一个数组中,并将其映射到您想要的格式。对象没有这样的功能。
  • @Y.Hewa 我已回滚您的编辑以保持问题清洁,希望您不介意。当您添加 Object.keys 后,该问题应该得到解决。只是出于好奇,为什么要删除它?
【解决方案3】:

你可以这样写。它是动态的。

var a = {}; 
for(var key in b["issues"]){ 
    if(!a.hasOwnProperty(b["issues"][key].fields.status.name)){
     a[b["issues"][key].fields.status.name] = 1;
    }else{
     a[b["issues"][key].fields.status.name] = a[b["issues"][key].fields.status.name]+1;
    }
}
var c = [];
for(var key1 in a){
   c.push({
   name  : key1,
   count : a[key1]
   });
}

【讨论】:

    【解决方案4】:

    使用 ES6 箭头函数,你可以用最少的语法来做到这一点

    var b = {
        "issues": [{
            "fields": {
                "status": {
                    "id": "200",
                    "name": "Backlog"
                }
            }
        }, {
            "fields": {
                "status": {
                    "id": "202",
                    "name": "close"
                }
            }
        }, {
            "fields": {
                "status": {
                    "id": "201",
                    "name": "close"
                }
            }
        }]
    };
    
    var countOfBackLog = b.issues.filter(x => {
    return x.fields.status.name === "Backlog"
    }).length
    
    var countOfClose = b.issues.filter(x => {
    return x.fields.status.name === "close"
    }).length
    
    a =[{Name: 'Backlog', count : countOfBackLog}, {Name: 'close', count : countOfClose}]
    

    更多关于箭头函数here

    【讨论】:

    • 其实你可以这样做:b.issues.filter(({fields:{status:{name}}}) => name === "Backlog").length
    • 当我们不知道属性名或属性名太多时,此方法将不起作用。
    猜你喜欢
    • 1970-01-01
    • 2023-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-24
    • 2013-02-19
    • 2020-02-13
    相关资源
    最近更新 更多