Javascript对象数组分组和求和

时间:2016-09-14 15:34:46

标签: javascript arrays object grouping aggregate-functions

我的任务是创建一个时间表,该表将显示每个客户每天工作的小时数。该表应该类似于下面的代码段:



table, td, th {
            border: 1px solid black;
        }

<div>
  <table id="testTable" class="table">
    <tr>
      <th>Client name</th>
      <th>Monday</th>
      <th>Tuesday</th>
      <th>Wednesday</th>
      <th>Thursday</th>
      <th>Friday</th>
      <th>Saturday</th>
      <th>Sunday</th>
    </tr>
    <tr>
      <td>client1</td>
      <td>0</td>
      <td>5</td>
      <td>3</td>
      <td>2</td>
      <td>3</td>
      <td>0</td>
      <td>0</td>
    </tr>
    <tr>
      <td>client2</td>
      <td>4</td>
      <td>1</td>
      <td>4</td>
      <td>2</td>
      <td>1</td>
      <td>0</td>
      <td>0</td>
    </tr>
  </table>
</div>
&#13;
&#13;
&#13; 我遇到的问题是,在查询填充表格所需的时间表项目后,我不确定如何按客户名称和星期几对每个项目进行分组。检索到的数组看起来类似于:

&#13;
&#13;
timesheetItems = [
  timesheetItem = {
      clientName: client1,
      hoursWorked: 2,
      day: Monday
    },
  timesheetItem = {
      clientName: client1,
      hoursWorked: 3,
      day: Monday
    },
  timesheetItem = {
      clientName: client1,
      hoursWorked: 4,
      day: Wednesday
    },
  timesheetItem = {
      clientName: client2,
      hoursWorked: 4,
      day: Monday
    }
  
  ];
&#13;
&#13;
&#13; 分组数组应该将每个时间表项目分组到每个客户端的一个对象中,并为每周的每一天提供密钥,其中包含当天工作的小时数。最终的数组看起来像这样:

&#13;
&#13;
groupedArray = {
  Client1 = {
    Mon: 5,
    tues: 3,
    ...
    sun: 0
  },
  client2 = {
    mon:2,
    ...
  },
  client3 = {
  ...
  },
  ...
}
&#13;
&#13;
&#13;

因此,如果有人可以建议如何对时间表项数组进行分组,以便结果看起来像上面的代码片段,那么我可以轻松地从分组数组循环以填充表,这将非常有帮助。 感谢。

3 个答案:

答案 0 :(得分:1)

要聚合数组,您可以使用reduce

const groupedArray = timesheetItems.reduce((prev, curr) => {
    if (!prev[curr.clientName]) {
        prev[curr.clientName] = {};
    }
    if (!prev[curr.clientName][curr.day]) {
        prev[curr.clientName][curr.day] = 0
    }
    prev[curr.clientName][curr.day] += curr.hoursWorked;
    return prev; 
}, {});

答案 1 :(得分:0)

您可以使用Array#forEach并检查是否存在对象。如果不存在,则分配新的对象或值。

var timesheetItems = [{ clientName: 'client1', hoursWorked: 2, day: 'Monday' }, { clientName: 'client1', hoursWorked: 3, day: 'Monday' }, { clientName: 'client1', hoursWorked: 4, day: 'Wednesday' }, { clientName: 'client2', hoursWorked: 4, day: 'Monday' }],
    grouped = {};

timesheetItems.forEach(a => {
    grouped[a.clientName] = grouped[a.clientName] || {};
    grouped[a.clientName][a.day] = (grouped[a.clientName][a.day] || 0) + a.hoursWorked;
});

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

答案 2 :(得分:0)

我们可以利用tableMaker()函数从对象数组生成表,其中每个对象指定一个表行,对象的属性指定标题,值是数据单元格。但首先我们必须将数据转换为tableMaker()函数可以理解的形式。如

[ { 'Client Name': 'client1',
    Monday: 5,
    Tuesday: 0,
    Wednesday: 4,
    Thursday: 0,
    Friday: 0 },
  { 'Client Name': 'client2',
    Monday: 4,
    Tuesday: 0,
    Wednesday: 0,
    Thursday: 0,
    Friday: 0 } ]

所以这是表格的代码。

&#13;
&#13;
function tableMaker(o,h=true){
  var keys = Object.keys(o[0]),
  rowMaker = (a,t) => a.reduce((p,c,i,a) => p + (i === a.length-1 ? "<" + t + ">" + c + "</" + t + "></tr>"
                                                                  : "<" + t + ">" + c + "</" + t + ">"),"<tr>"),
      rows = o.reduce((r,c) => r + rowMaker(keys.reduce((v,k) => v.concat(c[k]),[]),"td"),h ? rowMaker(keys,"th") : []);
  return "<table>" + rows + "</table>";
}

function giveMeNewClient(o){
  var templateObject = {
    	                "Client Name": "",
    	                     "Monday": 0,
    	                    "Tuesday": 0,
    	                  "Wednesday": 0,
    	                   "Thursday": 0,
    	                     "Friday": 0
                       };
  return Object.assign(templateObject,o);
}
var timesheetItems = [{
                        clientName: "client1",
                       hoursWorked: 2,
                               day: "Monday"
                      },
                      {
                      	clientName: "client1",
                       hoursWorked: 3,
                               day: "Monday"
                      },
                      {
                      	clientName: "client1",
                       hoursWorked: 4,
                               day: "Wednesday"
                      },
                      {
                      	clientName: "client2",
                       hoursWorked: 4,
                               day: "Monday"
                      }
                     ],

         tableData = timesheetItems.reduce((res,c) => { var client = res.find(o => o["Client Name"] === c.clientName);
                                                        client ? client[c.day]+= c.hoursWorked
                                                               : res.push(giveMeNewClient({"Client Name": c.clientName, [c.day]: c.hoursWorked}));
                                                        return res;
                                                      },[]),
         tableHTML = tableMaker(tableData);
myTable.innerHTML = tableHTML;
&#13;
<div id="myTable"></div>
&#13;
&#13;
&#13;