最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Grouping and summing in Ramda.js - Stack Overflow

programmeradmin4浏览0评论

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
Add a ment  | 

2 Answers 2

Reset to default 4

Heres 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.

发布评论

评论列表(0)

  1. 暂无评论