简体   繁体   English

在Ramda.js中分组和求和

[英]Grouping and summing in Ramda.js

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 combine 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). 我想组合两个列表中的数据,按Id分组,并使用结果中每个Id的最高日期,并总结唯一对象的总数(即具有相同Id和日期的对象 - 只能有一个每个日期和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: 我对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));

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 
// 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);

While it does appear to work, I'm wondering if there's a better way of solving this problem in Ramda? 虽然看起来确实有效,但我想知道在Ramda中是否有更好的方法来解决这个问题? The documention for groupBy indicates that it's not useful here. groupBy的文档表明它在这里没用

Updated version: jsFiddle 更新版本: jsFiddle

Heres a fiddle that uses the R.reduce function to avoid side-effects: http://jsfiddle.net/013kjv54/6/ 下面是一个使用R.reduce函数避免副作用的小提琴: http//jsfiddle.net/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 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));

You can see it in action on JSFiddle . 你可以在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. 与许多此类方法一样,它存在一个潜在的问题,即结果的顺序与底层JS引擎如何命令其对象关键参数有关,尽管这在现代引擎中大多是一致的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM