admin管理员组文章数量:1328037
I've got two lists:
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 },
];
I want to bine the data from both lists, grouping them by Id and using the highest date for each Id in the result, and summing the totals of the unique objects (ie. objects with the same Id and Date - there can only be one amount per Date and Id).
In other words, I want this result:
// "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}
]
I'm very new to Ramda, but I've managed to merge the lists using this code:
// Helper functions to build predicate list
var predicateListFunc = function (props) { return R.allPredicates(R.map(R.curry(R.eqProps), props)); }
var pareProperties = R.unapply(predicateListFunc);
// Function to merge lists based on object Ids and Dates
var mergeLists = R.unionWith(pareProperties("Id", "Date"));
// Function to sort in date descending order; used later to facilitate grouping
var sortByDateDesc = Rpose(R.reverse, R.sortBy(R.prop("Date")));
// Merge the lists
var mergedData = sortByDateDesc(mergeLists(listA, listB));
For grouping and summing:
// 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
// ment)
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);
While it does appear to work, I'm wondering if there's a better way of solving this problem in Ramda? The documention for groupBy indicates that it's not useful here.
Updated version: jsFiddle
I've got two lists:
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 },
];
I want to bine the data from both lists, grouping them by Id and using the highest date for each Id in the result, and summing the totals of the unique objects (ie. objects with the same Id and Date - there can only be one amount per Date and Id).
In other words, I want this result:
// "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}
]
I'm very new to Ramda, but I've managed to merge the lists using this code:
// Helper functions to build predicate list
var predicateListFunc = function (props) { return R.allPredicates(R.map(R.curry(R.eqProps), props)); }
var pareProperties = R.unapply(predicateListFunc);
// Function to merge lists based on object Ids and Dates
var mergeLists = R.unionWith(pareProperties("Id", "Date"));
// Function to sort in date descending order; used later to facilitate grouping
var sortByDateDesc = R.pose(R.reverse, R.sortBy(R.prop("Date")));
// Merge the lists
var mergedData = sortByDateDesc(mergeLists(listA, listB));
For grouping and summing:
// 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
// ment)
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);
While it does appear to work, I'm wondering if there's a better way of solving this problem in Ramda? The documention for groupBy indicates that it's not useful here.
Updated version: jsFiddle
Share Improve this question edited Nov 30, 2014 at 17:10 ilitirit asked Nov 30, 2014 at 14:43 ilitiritilitirit 16.4k19 gold badges77 silver badges116 bronze badges 2- 1 How about using ramda.reduce after grouping by id – Furqan Zafar Commented Nov 30, 2014 at 15:02
- I've reimplemented it using only R.reduce. I couldn't get it to work before because of a silly typo. Your suggestion made me double-check my original implementation and I spotted the error. – ilitirit Commented Nov 30, 2014 at 16:09
2 Answers
Reset to default 4Heres a fiddle that uses the R.reduce function to avoid side-effects: http://jsfiddle/013kjv54/6/
I only replaced your grouping code with the following:
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)));
I did not see this when the question was asked. If you're still interested in alternative approaches, here is a somewhat different way of doing this:
var bine = 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(bine, {}))
);
var result = process(R.concat(listA, listB));
You can see it in action on JSFiddle. As with many such approaches, it suffers from a potential problem in that the order of the results is tied to how the underlying JS engine orders its object key parameters, although that's mostly consistent across modern engines.
本文标签: javascriptGrouping and summing in RamdajsStack Overflow
版权声明:本文标题:javascript - Grouping and summing in Ramda.js - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742236551a2438188.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论