使用 ramda group by 属性 并对指定的 属性 的结果求和

using ramda group by property and sum results on specified property

我需要帮助使用 ramda 转换对象数组;我想

  1. 按指定分组 属性
  2. 求和另一个 属性 结果集

给定一个这样的数组:

var arr = [
  {
    title: "scotty",
    age: 22,
    score: 54,
    hobby: "debugging"

  },  {
    title: "scotty",
    age: 22,
    score: 19,
    hobby: "debugging"
  }
  ,  {
    title: "gabriel",
    age: 40,
    score: 1000
  }
];

如果我想按 title 分组并在 age 上求和,它应该 return 以下值摘要

var arr = [
  {
    title: "scotty",
    age: 44,
    hobby: "debugging",
  }
  ,  {
    title: "gabriel",
    age: 40,
    score: 1000
  }
];

当未指定的属性的值不同时,它们应该被省略,但如果未指定的属性的值相同,它应该保留在最终结果中。

** 我的解决方案 **

    /*
 * [Student]
 */
var arr = [
  {
    title: "scotty",
    age: 22,
    score: 54,
    hobby: "debugging"

  },  {
    title: "scotty",
    age: 22,
    score: 19,
    hobby: "debugging"
  }
  ,  {
    title: "gabriel",
    age: 40,
    score: 1000
  }
];


/*
 * String -> [[Student]] -> [Student]
 */
var sumOnProperty = function(property, v){
  var sum = (x,y) => x[property] + y[property];
  var new_array = [];
   v.forEach(arr => {
     if(arr.length > 1){
        arr[0]["age"] = arr.reduce(sum)
        new_array.push(arr[0]);
     } else {
       if(arr.length != 0){
        new_array.push(arr[0]);
       }
     }
   })
  return new_array;
}

/*
 * String -> String -> [Student] -> [Student]
 */
var groupsumBy = function(groupproperty, sumproperty, arr){ 

       // create grouping
       var grouping = R.groupBy(R.prop(groupproperty), arr)

       // convert grouping object to array 
       var result1 = R.valuesIn(grouping);

       // sum each grouping and flatten 2d array
       var result2 = sumOnProperty(sumproperty, result1);

       return result2;
}


groupsumBy("title","age",arr);

using ramda group by property and sum results on specified property

一个选项is to reduceBy如下:

import * as R from "ramda";

const arr = [
    {
        title: "scotty",
        age: 22,
        score: 54,
        hobby: "debugging"

    }, {
        title: "scotty",
        age: 22,
        score: 19,
        hobby: "debugging"
    }
    , {
        title: "gabriel",
        age: 40,
        score: 1000
    }
];

const reduction =
    R.reduceBy((acc, next) => acc + next.age, 0, (x) => x.title, arr);

console.log(JSON.stringify(reduction, undefined, 2));

输出已按 title 分组并已对 age 求和。

{                  
  "scotty": 44,    
  "gabriel": 40    
}                  

要解决您的 groupBy 问题,您需要了解 groupBy 采用密钥生成函数而不是二元谓词。

所以,例如,

const byTitle = R.groupBy(R.prop('title'));

这应该可以帮助您完成当前的障碍。如果您在求和方面需要帮助,请告诉我。

更新:

你问我方法。它确实和你的有点不同。我可能会做这样的事情:

const sumBy = prop => vals => reduce(
  (current, val) => evolve({[prop]: add(val[prop])}, current),
  head(vals),
  tail(vals)
)
const groupSumBy = curry((groupOn, sumOn, vals) => 
  values(map(sumBy(sumOn))(groupBy(prop(groupOn), vals)))
)

groupSumBy('title', 'age', people)

或者如果我想让它更简洁一点,我可能会切换到:

const sumBy = prop => lift(
  reduce((current, val) => evolve({[prop]: add(val[prop])}, current)
))(head, tail)

请注意,sumBy 相对可重用。它并不完美,因为它会在空列表上失败。但在我们的例子中,我们知道 groupBy 的输出永远不会为键创建这样一个空列表。任何没有在空列表上失败的版本都需要一种方法来提供默认情况。它只会变得丑陋。

您可以在 Ramda REPL.

上看到实际效果

如果您愿意先使用 groupOnsumOn 值调用,则可以使用 pipe or compose 制作更易于阅读的 groupSumBy 版本,然后调用具有值的结果函数,也就是说,如果调用如下所示:

groupSumBy('title', 'age')(people)
// or more likely:
const foo = groupSumBy('title', age)
foo(people)

但我将其留作 reader 的练习。