简体   繁体   English

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

[英]Match values of a key in a nested array of objects to an identifier key using ramda.js

I'm trying to take this array of nested objects and arrays and return a summed score for the identifier of that specific objects score into a new object. 我正在尝试使用此嵌套对象数组和数组,并将该特定对象的标识符的总和分数返回一个新对象。 Here is the JSON I'm working with: 这是我正在使用的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' }] }, }] } 

I'm trying to create an array of objects that have the sum of the score for each unique featureName and the corresponding featureName like this: 我正在尝试创建一个对象数组,该数组具有每个唯一的featureName和相应的featureName的得分总和,如下所示:

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

A solution that was close to what I was looking for can be found here , but matching the identifier with the sum was not shown in the solution. 可以在此处找到与我正在寻找的解决方案接近的解决方案,但是该解决方案中未显示将标识符与总和匹配。

Thank you in advance! 先感谢您!

I'm creating an object where I use the name of the feature as a key, so it's easy to create theirs total score. 我正在创建一个使用功能名称作为键的对象,因此很容易创建其总分。 Then I turn the object into an array matching your expectation. 然后,我将对象转换成符合您期望的数组。

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

Here's a solution with Ramda 这是Ramda的解决方案

 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) ); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script> 

I like to work out transformations like this a step at a time, starting with the original data, and working through to a final format. 我喜欢每次从原始数据开始,一直到最终格式,一次完成这样的转换。 I can do this inside Ramda's REPL with a pipe call, adding the individual calls one-by-one and checking that the results are moving toward what I want. 我可以通过pipe调用在Ramda的REPL中进行此操作,将单个调用一个接一个地添加,并检查结果是否朝着我想要的方向发展。

Doing so, this is the answer I come up with. 这样做,这就是我想出的答案。

 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> 

This demonstrates the structure of all the intermediate results: 这说明了所有中间结果的结构:

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}, ...] 

)

Note that if we drop off the last two lines ( toPairs and map(zipObj(...)) ), we get this format: 请注意,如果我们删除最后两行( toPairsmap(zipObj(...)) ), map(zipObj(...))得到以下格式:

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

which is often a more useful structure than your requested output. 这通常比您要求的输出更有用的结构。

And also note that this sort of work helps one identify useful functions one might want in our own utility library, or even to propose as additions to a library like Ramda. 还要注意的是,这种工作有助于人们在我们自己的实用程序库中识别可能想要的有用功能,甚至可以作为Ramda之类的库的补充而提出。 If I've done that toPairs / map(zipObj(...)) shuffle enough times, I might consider writing my own little function for it, such as: 如果我已经完成toPairs / map(zipObj(...))混洗足够多次,那么我可能会考虑为其编写自己的小函数,例如:

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

and then replace those two lines with objArray('featureName', 'summedScore') . 然后用objArray('featureName', 'summedScore')替换这两行。

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

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