Javascript Ramda.js中的分组和求和
我有两张清单:Javascript Ramda.js中的分组和求和,javascript,ramda.js,Javascript,Ramda.js,我有两张清单: var listA = [ { Id: 2, Date: "2014-11-28", Amount: 30 }, { Id: 1, Date: "2014-11-27", Amount: 15 }, { Id: 1, Date: "2014-11-28", Amount: 20 }, ]; var listB = [ { Id: 1, Date: "2014-11-27", Amount: 15 }, { Id: 2, Date: "
var listA =
[
{ Id: 2, Date: "2014-11-28", Amount: 30 },
{ Id: 1, Date: "2014-11-27", Amount: 15 },
{ Id: 1, Date: "2014-11-28", Amount: 20 },
];
var listB =
[
{ Id: 1, Date: "2014-11-27", Amount: 15 },
{ Id: 2, Date: "2014-11-26", Amount: 25 },
];
我想合并两个列表中的数据,按Id对它们进行分组,并在结果中使用每个Id的最高日期,并对唯一对象(即具有相同Id和日期的对象-每个日期和Id只能有一个数量)的总数进行求和
换句话说,我想要这个结果:
// "For ID X, the Amounts up to Date Y = total Z"
[
{"Id":1,"Date":"2014-11-28","Amount":35},
{"Id":2,"Date":"2014-11-28","Amount":55}
]
我对Ramda非常陌生,但我已经使用以下代码成功地合并了列表:
// Helper functions to build predicate list
var predicateListFunc = function (props) { return R.allPredicates(R.map(R.curry(R.eqProps), props)); }
var compareProperties = R.unapply(predicateListFunc);
// Function to merge lists based on object Ids and Dates
var mergeLists = R.unionWith(compareProperties("Id", "Date"));
// Function to sort in date descending order; used later to facilitate grouping
var sortByDateDesc = R.compose(R.reverse, R.sortBy(R.prop("Date")));
// Merge the lists
var mergedData = sortByDateDesc(mergeLists(listA, listB));
对于分组和求和:
// My original code used a side-effect because I could not get the R.reduce to
// work. Turns out it was a typo that prevented the initial list from propagating
// correctly. I reimplemented it and spotted the typo after reading Furqan Zafar's
// comment)
var groupCalc = function (list, item) {
var index = R.findIndex(R.propEq("Id", item.Id), list);
if (index >= 0) {
list[index].Amount += item.Amount;
} else
list.push(item);
return list;
};
var groupedList = R.reduce(groupCalc, [], mergedData);
虽然它看起来确实有效,但我想知道在拉姆达是否有更好的方法来解决这个问题?的文档表明它在这里没有用处
更新版本:这里有一把小提琴,它使用R.reduce功能来避免副作用: 我仅将您的分组代码替换为以下代码:
var result = R.reduce(function(acc, tuple){
acc.push({
StockId: tuple[0],
Reference: R.maxBy(function(record){return new Date(record.Reference)}, tuple[1]).Reference,
Amount: R.reduce(function(acc, record){return acc + record.Amount}, 0, tuple[1])
});
return acc;
}, [], R.toPairs(R.groupBy(function(record){return record.StockId})(mergedData)));
当有人问这个问题时,我没有看到这一点。如果您仍然对其他方法感兴趣,这里有一种不同的方法:
var combine = function(acc, entry) {
return {
Id: entry.Id,
Date: acc.Date && acc.Date > entry.Date ? acc.Date : entry.Date,
Amount: (acc.Amount || 0) + entry.Amount
};
};
var process = R.pipe(
R.groupBy(R.prop('Id')),
R.values,
R.map(R.uniqWith(R.eqProps('Date'))),
R.map(R.reduce(combine, {}))
);
var result = process(R.concat(listA, listB));
您可以在上看到它的作用。与许多这样的方法一样,它也面临着一个潜在的问题,即结果的顺序与底层JS引擎对其对象键参数的顺序有关,尽管这在现代引擎中基本一致。使用ramda.reduce如何通过idI分组后,我仅使用R.reduce重新实现了它。因为一个愚蠢的打字错误,我以前无法让它工作。你的建议让我仔细检查了我最初的实现,我发现了错误。谢谢。我没有想到在分组数据后创建元组。我不确定它是否比使用程序比较快,但至少我学会了一些新技术!顺便说一句,您可以使用curried库函数来缩短一些函数,例如R.prop(“StockId”)将返回StockId。感谢您提供的提示,但我主要使用livescript和prelude ls,Ramda与prelude非常相似。如果您对使用javascript进行函数式编程感兴趣,您应该结帐&