【问题标题】:Summarize/tally array with reduce function使用reduce函数汇总/计数数组
【发布时间】:2020-01-28 19:53:18
【问题描述】:

我是 JS 新手,在为里程应用程序汇总 Google 电子表格数据数组时遇到了障碍。

我正在尝试计算由员工 ID 和日期驱动的里程,但没有找到在线资源来使用 reduce/filter 执行此级别的功能。


var records = [
    ["2019-08-26", emp1, 111],
    ["2019-08-26", emp2, 79],
    ["2019-09-02", emp1, 111],
    ["2019-09-02", emp2, 59],
    ["2019-09-02", emp3, 22],
    ["2019-09-05", emp3, 26],
    ["2019-09-02", emp1, 12],
    ["2019-09-05", emp3, 50],
    ["2019-09-02", emp2, 49],
    ["2019-09-05", emp1, 69],
    ["2019-09-02", emp1, 42],
    ["2019-09-05", emp3, 21],
    ["2019-09-02", emp2, 101],
    ["2019-09-05", emp3, 78],
    ["2019-09-02", emp3, 35],
    ["2019-09-05", emp1, 47]
]

我已经尝试过 for 循环和 reduce/map 组合,但我无法让代码以我们想要的方式返回数据。最好的尝试是使用 reduce 功能,所以我认为我走在正确的轨道上?我还尝试仅将日期映射到单独的数组中以进行匹配,但不确定这是否会使它变得更复杂。

日期、员工和里程会不断变化,因此我必须使用的方法必须是动态的,以适应未来的员工、日期和数百条记录。

我做错了什么?

var summary = records.reduce(function(total, employee) {
    total[employee[0]] = total[employee[0]] || []
    total[employee[0]].push({
        date: employee[0], 
        eid: employee[1],
        miles: employee[2]      
    }) 
    return total                                                              
  },{})

更新:在计算了一天和员工的行驶里程后,我被要求确定“firstTrip”。我已经尝试将Math.max()Math.min() 嵌入到答案中的代码中,但不认为这是正确的方法。关于我应该如何处理这个新的发展有什么想法吗?

[
  {date: "2019-08-26", employee: emp1, miles: 111, firstTrip: 111},
  {date: "2019-08-26", employee: emp2, miles: 79, firstTrip: 79},
  {date: "2019-09-02", employee: emp1, miles: 65, firstTrip: 12},
  {date: "2019-09-02", employee: emp2, miles: 209, firstTrip: 49},
  {date: "2019-09-02", employee: emp3, miles: 57, firstTrip:22}, 

etc

]

由于 Google 表格数据,我在 Google AppScript (GAS) 环境中工作。任何帮助将不胜感激。

【问题讨论】:

  • 您是否要合并重复的日期/员工?
  • 嗨,Light,是的,我希望每位员工只有一次约会和总和。本质上,我试图总结数据,就像在 Excel 上的数据透视表中一样,其中所有重复项合并为一个并对值求和。

标签: javascript google-apps-script reduce


【解决方案1】:

在您的尝试中,您正在做的是使用日期键和该日期中的所有不同条目(如值)来索引对象,如下所示:

{
    "2019-08-26": [
        {date: "2019-08-26", employee: emp1, miles: 111},
        {date: "2019-08-26", employee: emp2, miles: 79}
    ],
    "2019-09-02": [
        {date: "2019-09-02", employee: emp1, miles: 111},
        {date: "2019-09-02", employee: emp2, miles: 59},
        {date: "2019-09-02", employee: emp3, miles: 22}
    ],
    etc...
}

如果我理解你想要做什么,你需要像reduce 的第二个参数一样传递一个数组[],而不是一个对象{}

在每次迭代之后,您必须检查是否已经存在具有给定日期和员工的元素。如果不是,则推送该元素,如果是,则将英里添加到给定对象。

代码会是这样的:

var summary = records.reduce( (total,record) => {
    var index = total.findIndex( s => s.date == record[0] && s.employee == record[1] );
    if( index == -1 ){
            total.push( {date: record[0], employee: record[1], miles: record[2]} );
    }else{
            total[ index ].miles += record[2];
    }
    return total;
},[]);

你会得到这个结果:

[
    {"date":"2019-08-26","employee":emp1,"miles":111},
    {"date":"2019-08-26","employee":emp2,"miles":79},
    {"date":"2019-09-02","employee":emp1,"miles":165},
    {"date":"2019-09-02","employee":emp2,"miles":209},
    {"date":"2019-09-02","employee":emp3,"miles":57},
    {"date":"2019-09-05","employee":emp3,"miles":175},
    {"date":"2019-09-05","employee":emp1,"miles":116}
]

已编辑: 对于 Google APPS 脚本,试试这个:

var summary = records.reduce( function(total,record){
    var index = -1;
    total.forEach( function(s,i){
        if( s.date == record[0] && s.employee == record[1] ) index = i;
    });
    if( index == -1 ){
        total.push( {date: record[0], employee: record[1], miles: record[2]} );
    }else{
        total[ index ].miles += record[2];
    }
    return total;
},[]);

【讨论】:

  • 谢谢@Macarthurval。是否有相当于findIndex 的 Google App 脚本?我正在尝试IndexOf,但我认为这不是一回事。没有它,它会返回相同数量的不同排列的项目,类似于使用.map
  • 我已经更新了替换 findIndex 部分的答案。
  • @haby22 如果对您正确,请接受答案。
  • 嗨@Macarthurval,感谢您的帮助。我被要求提供有关我似乎无法用Math.min() 破解的阵列的更多信息。任何想法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-01
  • 2019-10-28
  • 2023-04-03
  • 1970-01-01
  • 2014-11-25
  • 2017-12-27
  • 1970-01-01
相关资源
最近更新 更多