Javascript 组合对象数组及其属性。合并后删除对象
我需要将这些对象合并在一起。资源属性决定是否可以合并对象。要确定小时属性值的去向,请使用可计费属性。我希望数组看起来像这样Javascript 组合对象数组及其属性。合并后删除对象,javascript,Javascript,我需要将这些对象合并在一起。资源属性决定是否可以合并对象。要确定小时属性值的去向,请使用可计费属性。我希望数组看起来像这样 members = [{billable: true, hours: 15, name: "Joe Smith", resource: "00530000003mgYGAAY", totalBillableHours: 20, totalHours: 25, totalNonBillableHours: 5}, {billable: false, hours: 5, nam
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属性的状态是不相关的
这是密码。我似乎不明白为什么它不起作用
当您在数组上迭代时从数组中删除项时,它会变得非常棘手 我在这里以更实用的方式重写了您的解决方案: 结果输出就是您要查找的内容:
Array[2]
0 : Object
billable : true
hours : 15
name : "Joe Smith"
resource : "00530000003mgYGAAY"
totalBillableHours : 20
totalHours : 25
totalNonBillableHours : 5
__proto__ : Object
1 : Object
billable : false
hours : 5
name : "Jan Smith"
resource : "00530000003mgYTAAY"
totalBillableHours : 14
totalHours : 19
totalNonBillableHours : 5
__proto__ : Object
length : 2
__proto__ : Array[0]
问题是您依赖于每个记录的相邻记录。相反,您可以根据每个成员的资源对其进行计数。由于资源是唯一的,所以可以将其用作保持计数的对象的属性—将其视为一个键。然后可以将每个记录中的小时数添加到相应的对象中 以下是我的尝试:
一种技术是在每个成员上循环,找到第一个包含该资源的成员,更新其中的总数,然后进行筛选,以便只保留第一次出现的成员
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]
}
首先计算总数,那将是
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};
});
}
总和可以写成
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;
}, {});
}
以下是使用库免责声明的版本:我是作者之一:
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收集相似的值,并使用值将结果提取为数组
然后,它映射到生成的组列表,通过适当地组合字段将每个组减少为单个值
这可能对您没有多大帮助,因为仅仅为了一项任务而引入Ramda这样的库可能是一个荒谬的想法。但你可能会从问题的分解中得到灵感
这里使用的大多数Ramda函数都很容易自己创建,并且在许多方面都非常有用
您可以在屏幕上看到这一点。这太尴尬了。。。你只是想知道如何将每个资源的所有计费小时数相加吗?这里的问题是什么?@BradEvans,不止这些。我需要在angular应用程序上显示两个单独的对象。在脑海中、在纸上或黑板上浏览代码,或者找人讨论代码,或者使用调试器浏览代码。你应该很快找到你的问题。@torazaburo相信我,我不会发帖的,除非我已经花了几个小时在上面。我迷路了。我同意这个解决方案很尴尬。请参阅下面的任何答案。常见的主题是不要尝试在阵列中执行此操作。这就是为什么很难理解。我很感激你的尝试,但这不是我想要的。我需要属性字段TimeBelabl小时、ToalTimes和Tun-ByBelabl小时更新。@ Tyelrigka我已经更新了答案来考虑Brable属性并输出您正在寻找的结果。这是一个可怕的滥用过滤器,但我不得不承认它导致非常简单的代码。但可悲的是,也没有那么优雅!;-不过,我可能会选择它,而不是这里的其他答案。如果我已经在使用Ramda,我会选择下面的答案。根据人们对可重用部件的期望程度,小时数可以用更通用的prop/get/property函数来编写。maphours可能是“hours”,等等。。。很快你就要建一个图书馆了!很抱歉写信给你。。。我发现您是ramdajs的顶级用户,因此我想问您是否有时间快速查看我的问题,我非常感谢您的反馈。提前谢谢你的专业知识@GibboK:我已经玩过一点了。我会回复的。谢谢斯科特,我真的很感谢你的时间和帮助。
function groupBy(arr, prop) {
return arr.reduce((result, obj) {
const key = obj[prop];
if (!result[key]) result[key] = [];
result[key].push(obj);
return result;
}, {});
}
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
}
]