使用ramda.js将嵌套对象数组中的键的值与标识符键匹配

时间:2019-01-17 13:54:53

标签: javascript arrays nested iteration ramda.js

我正在尝试使用此嵌套对象数组和数组,并将该特定对象的标识符的总和得分返回一个新对象。这是我正在使用的JSON:

{
   "AllData" : [ {
        "company" : google,
        "featureData" : [{
           "ScoreTotal" : 10, 
           "featureName": 'test' 
           },{
           "ScoreTotal" : 10, 
           "featureName": 'test2' 
           },
           {
           "ScoreTotal" : 4, 
           "featureName": 'test3' 
           }]
        }, {
        "company" : amazon,
        "featureData" : [{
           "ScoreTotal" : 4, 
           "featureName": 'test' 
           },{
           "ScoreTotal" : 6, 
           "featureName": 'test2' 
           },
           {
           "ScoreTotal" : 3, 
           "featureName": 'test3' 
           }]
        },{
        "company" : facebook,
        "featureData" : [{
           "ScoreTotal" : 4, 
           "featureName": 'test' },
           {
           "ScoreTotal" : 6, 
           "featureName": 'test2' },
           {
           "ScoreTotal" : 2, 
           "featureName": 'test3' 
           }]
        }, 
   }]
}

我正在尝试创建一个对象数组,该数组具有每个唯一featureName和相应featureName的得分总和,如下所示:

[{featureName:'test1',summedScore:'18'},{featureName:'test2',summedScore:'22'},{featureName:'test3',summedScore:'9'}]

可以找到here接近我所寻找的解决方案,但是该解决方案中未显示将标识符与总和匹配。

提前谢谢!

3 个答案:

答案 0 :(得分:0)

我正在创建一个对象,其中使用功能名称作为键,因此很容易创建其总分。然后,我将对象转换成符合您期望的数组。

const json = {
  "AllData": [{
      "company": 'google',
      "featureData": [{
          "ScoreTotal": 10,
          "featureName": 'test'
        }, {
          "ScoreTotal": 10,
          "featureName": 'test2'
        },
        {
          "ScoreTotal": 4,
          "featureName": 'test3'
        }
      ]
    }, {
      "company": 'amazon',
      "featureData": [{
          "ScoreTotal": 4,
          "featureName": 'test'
        }, {
          "ScoreTotal": 6,
          "featureName": 'test2'
        },
        {
          "ScoreTotal": 3,
          "featureName": 'test3'
        }
      ]
    }, {
      "company": 'facebook',
      "featureData": [{
          "ScoreTotal": 4,
          "featureName": 'test'
        },
        {
          "ScoreTotal": 6,
          "featureName": 'test2'
        },
        {
          "ScoreTotal": 2,
          "featureName": 'test3'
        }
      ]
  }]
};

const obj = json.AllData.reduce((tmp, x) => {
  x.featureData.forEach((y) => {
    tmp[y.featureName] = (tmp[y.featureName] || 0) + y.ScoreTotal;
  });

  return tmp;
}, {});

const arr = Object.keys(obj).map(x => ({
  summedScore: obj[x],
  featureName: x,
}));

console.log(arr);

答案 1 :(得分:0)

这是Ramda的解决方案

sed -e 's/,/./1;p' \
    -e ':a' \
    -e 's/^\(\([^.]*[.][^,]*,\)*\)\([^,]*\),\([^,]*\)/\1\3.\4/
        /[^,]*,[^,.]*,/ ta' YourFile
const data = {
  "AllData": [{
    "company": "google",
    "featureData": [{
      "ScoreTotal": 10,
      "featureName": 'test'
    }, {
      "ScoreTotal": 10,
      "featureName": 'test2'
    },
    {
      "ScoreTotal": 4,
      "featureName": 'test3'
    }]
  }, {
    "company": "amazon",
    "featureData": [{
      "ScoreTotal": 4,
      "featureName": 'test'
    }, {
      "ScoreTotal": 6,
      "featureName": 'test2'
    },
    {
      "ScoreTotal": 3,
      "featureName": 'test3'
    }]
  }, {
    "company": "facebook",
    "featureData": [{
      "ScoreTotal": 4,
      "featureName": 'test'
    },
    {
      "ScoreTotal": 6,
      "featureName": 'test2'
    },
    {
      "ScoreTotal": 2,
      "featureName": 'test3'
    }]
  }
  ]
};

const getScores =
  R.pipe(
    // Group all featureData objects into a single array
    R.prop('AllData'),
    R.map(R.prop('featureData')),
    R.unnest,
    
    // Group all featureData objects with the same featureName into separate arrays
    R.groupBy(R.prop('featureName')),
    
    // Merge all objects in each array by summing their `ScoreTotal` properties
    R.map(R.reduce(R.mergeWithKey((key, left, right) => key === 'ScoreTotal' ? left + right : right), {})),
    R.values,
    
    // Reshape each object
    R.map(R.applySpec({
      featureName: R.prop('featureName'),
      summedScore: R.prop('ScoreTotal')
    })));

console.log(

  getScores(data)

);

答案 2 :(得分:0)

我喜欢每次从原始数据开始,一直到最终格式,一次完成这样的转换。我可以在Ramda's REPL内进行一次pipe调用,将单个调用一个接一个地添加,并检查结果是否朝着我想要的方向移动。

这样做,这就是我想出的答案。

const {pipe, prop, pluck, unnest, groupBy, map, sum, toPairs, zipObj} = R

const sumByFeatureName = pipe(
  prop('AllData'),
  pluck('featureData'),
  unnest,
  groupBy(prop('featureName')),
  map(pluck('ScoreTotal')),
  map(sum),
  toPairs,
  map(zipObj(['featureName', 'summedScore'])),
)

const json = {"AllData": [{"company": "google", "featureData": [{"ScoreTotal": 10, "featureName": "test"}, {"ScoreTotal": 10, "featureName": "test2"}, {"ScoreTotal": 4, "featureName": "test3"}]}, {"company": "amazon", "featureData": [{"ScoreTotal": 4, "featureName": "test"}, {"ScoreTotal": 6, "featureName": "test2"}, {"ScoreTotal": 3, "featureName": "test3"}]}, {"company": "facebook", "featureData": [{"ScoreTotal": 4, "featureName": "test"}, {"ScoreTotal": 6, "featureName": "test2"}, {"ScoreTotal": 2, "featureName": "test3"}]}]}

console.log(sumByFeatureName(json))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

这说明了所有中间结果的结构:

const sumByFeatureName = pipe(
  prop('AllData'),                              //=> [{company: "google", featureData: [{ScoreTotal: 10, featureName: "test"}, ...], {company: 'amazon', ...}, ...]
  pluck('featureData'),                         //=> [[{ScoreTotal: 10, featureName: 'test"}, {ScoreTotal: 10, featureName: 'test2'}, ...] [...], ...]
  unnest,                                       //=> [{ScoreTotal: 10, featureName: 'test'}, {ScoreTotal: 10, featureName: 'test2'}, ...]  
  groupBy(prop('featureName')),                 //=> {test: [{ScoreTotal: 10, featureName: 'test'}, ...], test2: [{...}, ...]}
  map(pluck('ScoreTotal')),                     //=> {test: [10, 4, 4], test2: [10, 6, 6], test3: [4, 3, 2]} 
  map(sum),                                     //=> {test: 18, test2: 22, test3: 9}
  toPairs,                                      //=> [['test', 18], ['test2', 22], ['test3', 9]]
  map(zipObj(['featureName', 'summedScore'])),  //=> [{featureName: 'test, summedScore: 19}, ...] 

请注意,如果我们删除最后两行(toPairsmap(zipObj(...))),则会得到以下格式:

{test: 18, test2: 22, test3: 9}

通常是比您要求的输出更有用的结构。

还要注意,这种工作有助于人们识别自己可能希望在我们自己的实用程序库中使用的有用功能,甚至可以作为对Ramda之类的库的补充。如果我已经完成toPairs / map(zipObj(...))的混洗足够的次数,则可以考虑为其编写自己的小函数,例如:

const objArray = (keyName, valName) => vals => 
  map(zipObj([keyName, valName]), toPairs(vals))

,然后将这两行替换为objArray('featureName', 'summedScore')