我需要将对象合并在一起。 resource
属性决定了对象是否可以合并。要确定hours
属性值的位置,请使用billable
属性。我希望数组看起来像这样
members = [{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 20, totalHours: 25, totalNonBillableHours: 5},
{billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 14, totalHours: 19, totalNonBillableHours: 10}]
最终结果的billable
和hours
属性状态无关紧要。
这是代码。似乎无法弄清楚它为什么不起作用。
http://codepen.io/anon/pen/MbOdmV?editors=0002
members = [
{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 12, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 2, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0}
];
for (i = 0; i < members.length; i++) {
var member = members[i];
if (member.resource == members[i + 1].resource) {
if(member.billable == true) {
member.totalBillableHours += members[i + 1].hours;
}
else {
member.totalNonBillableHours += members[i + 1].hours;
}
member.totalHours += members[i + 1].hours;
members.splice(i + 1, 1);
--i;
if (members[i + 2] == undefined) {
break;
}
}
}
console.log(members);
答案 0 :(得分:2)
在迭代数组时从数组中删除项目时会非常棘手。
我在这里以更实用的方式重写了您的解决方案:http://codepen.io/tinacious/pen/gLXJow?editors=1011
ArgumentError: unknown option: {:profile=>#<Selenium::WebDriver::Firefox::Profile:0x000000068ca798 @model=nil, @native_events=true, @secure_ssl=false, @untrusted_issuer=true, @load_no_focus_lib=false, @additional_prefs={}, @extensions={}>}
结果输出是您正在寻找的:
var members = [
{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 12, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 2, name: "Jam Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0}
];
function combineMembers(members) {
var combinedMembers = {};
members.forEach(function (member) {
var resourceId = member.resource;
var typeOfHour = member.billable ? 'totalBillableHours' : 'totalNonBillableHours';
if (!combinedMembers[resourceId]) {
combinedMembers[resourceId] = Object.assign({}, member);
}
combinedMembers[resourceId][typeOfHour] += member.hours;
combinedMembers[resourceId].totalHours += member.hours;
});
return Object.keys(combinedMembers).map(function (resourceId) {
return combinedMembers[resourceId];
});
}
console.log(combineMembers(members));
答案 1 :(得分:2)
问题是你依赖于每条记录的相邻记录。相反,您可以通过member
保持每个resource
的计数。由于resource
是唯一的,因此您可以将其用作保持计数的对象的属性 - 将其视为关键字。然后,您可以将每条记录中的小时数添加到相应的对象中。
这是我的尝试:http://codepen.io/anon/pen/bBYyPa
var members = [
{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: false, hours: 5, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 12, name: "Jan Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0},
{billable: true, hours: 2, name: "Jam Smith", resource: "00530000003mgYTAAY", totalBillableHours: 0, totalHours: 0, totalNonBillableHours: 0}
];
var membersObj = {};
for (i = 0; i < members.length; i++) {
var member = members[i];
if (!membersObj[member.resource]){
membersObj[member.resource] = members[i];
}
if(member.billable){
membersObj[member.resource].totalBillableHours += member.hours;
} else {
membersObj[member.resource].totalNonBillableHours += member.hours;
}
membersObj[member.resource].totalHours += member.hours;
}
console.log(membersObj);
当然,这会让你返回一个对象而不是一个数组,但如果需要可以转换它。
这是输出:
{
'00530000003mgYGAAY':
{ billable: true,
hours: 15,
name: 'Joe Smith',
resource: '00530000003mgYGAAY',
totalBillableHours: 20,
totalHours: 25,
totalNonBillableHours: 5 },
'00530000003mgYTAAY':
{ billable: false,
hours: 5,
name: 'Jan Smith',
resource: '00530000003mgYTAAY',
totalBillableHours: 14,
totalHours: 19,
totalNonBillableHours: 5 }
}
答案 2 :(得分:1)
一种技术是循环遍历每个成员,找到第一个拥有该资源的成员,更新其中的总数,然后进行过滤以便仅保留第一次出现。
members.filter(member => {
const first = members.find(m => m.resource === member.resource);
if (member.billable) first.totalBillableHours += member.hours;
else first.totalNonBillableHours += member.hours;
first.totalHours += member.hours.
return first === member;
});
更正统的方法是按资源对对象进行分组,为每个资源创建一个对象数组,然后将其转换为所需的输出,如
totals(groupBy(members, 'resource'))
groupBy
将被定义为生成以下形式的内容:
{
resource1: [obj, obj],
resource2: [obj, obj]
}
首先取totals
,即
function totals(groups) {
const hours = m => m.hours;
const billable = m => m.billable;
const not = f => x => !f(x);
return Object.keys(groups).map(resource => {
const members = groups[resource];
const totalHours = sum(members.map(hours));
const billableHours = sum(members.filter(billable).map(hours));
const nonBillableHours = sum(members.filter(not(billable)).map(hours));
return {resource, totalHours, billableHours, nonBillableHours};
});
}
sum
可以写成
const sum = arr => arr.reduce((a, b) => a + b, 0);
那里有许多groupBy
的实现,包括由库提供的诸如下划线的实现。这是一个真正简单的版本:
function groupBy(arr, prop) {
return arr.reduce((result, obj) {
const key = obj[prop];
if (!result[key]) result[key] = [];
result[key].push(obj);
return result;
}, {});
}
答案 3 :(得分:1)
这是使用Ramda库的版本(免责声明:我是其中一位作者):
const process = pipe(
groupBy(prop('resource')),
values,
map(group => reduce((totals, member) => ({
name: member.name,
resource: member.resource,
totalHours: totals.totalHours + member.hours,
totalBillableHours: totals.totalBillableHours +
(member.billable ? member.hours : 0),
totalNonBillableHours: totals.totalNonBillableHours +
(member.billable ? 0 : member.hours)
}), head(group), group))
);
有了这个,
process(members)
产量
[
{
name: "Joe Smith",
resource: "00530000003mgYGAAY",
totalBillableHours: 20,
totalHours: 25,
totalNonBillableHours: 5
},
{
name: "Jam Smith",
resource: "00530000003mgYTAAY",
totalBillableHours: 14,
totalHours: 19,
totalNonBillableHours: 5
}
]
这分两个阶段进行。首先,它收集相似的值(使用groupBy
)并将结果提取为数组(使用values
)。
然后,它会映射生成的组列表,通过合并这些字段将每个组减少为单个值。
这对你来说可能没什么帮助,因为拉一个像Ramda这样的图书馆来完成一项任务可能是一个荒谬的想法。但是你可能会在问题崩溃时获得灵感。
这里使用的大多数Ramda函数都很容易自己创建,对于很多用途非常有用。
您可以在 Ramda REPL 上看到这一点。