重构 if else 语句以使用 Ramda.js 并将键值对分解为对象记录

refactoring if else statement to use Ramda.js & breaking down key value pairs into object records

我想将下面的 reducer 函数转换为使用 ramda。而不是使用 JS if else 语句,我怎么能使用 R.ifElse()

来做到这一点
var groupAndSumBy = (objKey) => 
    R.reduce(function(acc, val){
                var accKey = val[objKey]
                acc = Object.assign({}, acc)
                if ( acc.hasOwnProperty(accKey) ){
                    acc[accKey] = acc[accKey] + totalInvoice(val)
                } else {
                    acc[accKey] = totalInvoice(val)
                }
                return acc
}, {})

var sumByCountry = groupAndSumBy("MARKET")

var vals =[
    {
        "COUNTRY": "AUSTRIA",
        "TYPE": "SERVICES",
        "AMT1": 2555.05,
        "AMT2": 2686.48,
        "AMT3": 2805.1,
        "AMT4": 2732.23
    },
    {
        "COUNTRY": "GERMANY",
        "TYPE": "SERVICES",
        "AMT1": 2555.05,
        "AMT2": 2686.48,
        "AMT3": 2805.1,
        "AMT4": 2732.23
    },
    {
        "COUNTRY": "UK",
        "TYPE": "SERVICES",
        "AMT1": 2555.05,
        "AMT2": 2686.48,
        "AMT3": 2805.1,
        "AMT4": 2732.23
    },
]

想要的输出如下

sumByCountry(vals)

{
    'AUSTRIA': 10778.86,
    'GERMANY': 10777.86,
    'UK': 10777.86,
}

此外,我想将上面所需的输出分解为单独的记录,这是我无法使用 ramda 实现的。

[
    {index:'AUSTRIA', value: 10777.86},
    {index:'GERMANY', value: 10777.86},
    {index:'UK', value: 10777.86}
]

阿兰! 我认为无论如何您都需要使用 lambda,但是如果您想将 if 语句更改为 Ramda 的语句,这可能是解决方案吗? 它更聪明一点,但选择权在你。

const groupAndSumBy = objKey =>
  R.reduce((acc, val) => {
    const invoice = totalInvoice(val)
    const accKey = val[objKey]

    return R.ifElse(
      R.has(accKey),
      R.assoc(accKey, invoice + acc[accKey]),
      R.assoc(accKey, invoice)
    )(acc)
  }, {})

此函数会将结果准备为您需要的格式:

const groupAndSumBy = objKey => vals => R.pipe(
  R.reduce((acc, val) => {
    const invoice = totalInvoice(val)
    const accKey = val[objKey]

    return R.ifElse(
      R.has(accKey),
      R.assoc(accKey, invoice + acc[accKey]),
      R.assoc(accKey, invoice)
    )(acc)
  }, {}),
  R.toPairs,
  R.map(p => ({ index: p[0], value: p[1] }))
)(vals)

我会首先定义一个函数,对一个对象的属性求和,如果它们是数字:

const sumObj = compose(sum, values, filter(is(Number)));

sumObj({
  "COUNTRY": "AUSTRIA",
  "TYPE": "SERVICES",
  "AMT1": 2555.05,
  "AMT2": 2686.48,
  "AMT3": 2805.1,
  "AMT4": 2732.23
});
//=> 10778.86

然后您可以使用 reduceBy 通过 COUNTRY 将您的对象分组在一起并在每个对象上应用 sumObj。之后使用 aggregate 将您的对象分解为单独的记录:

var vals = [
  { "COUNTRY": "AUSTRIA",
    "TYPE": "SERVICES",
    "AMT1": 2555.05,
    "AMT2": 2686.48,
    "AMT3": 2805.1,
    "AMT4": 2732.23 },

  { "COUNTRY": "AUSTRIA",
    "TYPE": "SERVICES",
    "AMT1": 2555.05,
    "AMT2": 2686.48,
    "AMT3": 2805.1,
    "AMT4": 2732.23 },

  { "COUNTRY": "GERMANY",
    "TYPE": "SERVICES",
    "AMT1": 2555.05,
    "AMT2": 2686.48,
    "AMT3": 2805.1,
    "AMT4": 2732.23 },

  { "COUNTRY": "UK",
    "TYPE": "SERVICES",
    "AMT1": 2555.05,
    "AMT2": 2686.48,
    "AMT3": 2805.1,
    "AMT4": 2732.23 } ];

const sumObj = compose(sum, values, filter(is(Number)));
const sumObjs = reduceBy((acc, obj) => acc + sumObj(obj), 0, prop('COUNTRY'));
const aggregate = compose(map(zipObj(['index', 'value'])), toPairs, sumObjs);

console.log(

  aggregate(vals)

)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {map, zipObj, reduceBy, prop, compose, sum, applySpec, values, filter, is, toPairs} = R;</script>