使用ramda按属性分组并求和指定属性的结果

Jon*_*eal 6 javascript typescript ramda.js

我需要使用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
  }
];
Run Code Online (Sandbox Code Playgroud)

如果我要分组title并求和,age则应返回以下值汇总

var arr = [
  {
    title: "scotty",
    age: 44,
    hobby: "debugging",
  }
  ,  {
    title: "gabriel",
    age: 40,
    score: 1000
  }
];
Run Code Online (Sandbox Code Playgroud)

当未指定属性的值不同时,应将其省略,但如果未指定属性的值相同,则应保留在最终结果中。

**我的解决方案**

    /*
 * [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);
Run Code Online (Sandbox Code Playgroud)

Sco*_*yet 6

要解决您的groupBy问题,您需要看到它groupBy采用键生成函数而不是二进制谓词。

因此,例如

const byTitle = R.groupBy(R.prop('title'));
Run Code Online (Sandbox Code Playgroud)

这应该使您了解当前的障碍。如果您需要有关汇总的帮助,请告诉我。

更新

你问我的方法。确实与您的确有所不同。我可能会做这样的事情:

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)
Run Code Online (Sandbox Code Playgroud)

或者,如果我想更简洁一些,可以切换到:

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

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

您可以在Ramda REPL上看到这一点。

你也许可以做的更容易阅读的版本groupSumBy使用pipe或者compose ,如果你愿意与第一调用groupOnsumOn值,然后调用与价值观所产生的功能,也就是说,如果调用是这样的:

groupSumBy('title', 'age')(people)
// or more likely:
const foo = groupSumBy('title', age)
foo(people)
Run Code Online (Sandbox Code Playgroud)

但我将其留给读者练习。