1

I have an array of array of objects. I want to reduce that to an array of object and adding one more property to each object. The sample input is:

const data = [
    [
        {name:"a", val:5},
        {name:"b", val:10},
        {name:"c", val:20},
        {name:"d", val:50},
        {name:"e", val:100}
    ],
    [
        {name:"a", val:0},
        {name:"b", val:20},
        {name:"c", val:30},
        {name:"d", val:40},
        {name:"e", val:10}
    ],
    [
        {name:"a", val:60},
        {name:"b", val:50},
        {name:"c", val:40},
        {name:"d", val:70},
        {name:"e", val:30}
    ]
];

And the Output should be:

[{name: 'a', val: 65, rank: 'si'},
 {name: 'b', val: 80, rank: 'dp'},
 {name: 'c', val: 90, rank: 'en'}
 {name: 'd', val: 160, rank: 'fr'}]

Rank is static text means for a, it will always be "si" How can I achieve this using ramda?

4
  • 1
    Are we to guess as to how the rank is generated? Grouping and summing is covered by a few different questions: using ramda group by property and sum results on specified property, Grouping and summing in Ramda.js, How to group by a key and sum other keys with Ramda? Commented Jan 6, 2021 at 20:01
  • that is static text. Commented Jan 6, 2021 at 20:02
  • I am assuming the a, b, c, d in the resulting array are the sum of all as, bs, cs, ds in the original array but since your b total is incorrect and should be 80 instead of 90 if you follows that pattern, I have to ask are those actually sums or is there some other algorithm? Commented Jan 6, 2021 at 20:05
  • @codemonkey yes, I have corrected that :) That is actually sum Commented Jan 6, 2021 at 20:06

1 Answer 1

3

You can convert flatten all sub arrays to a single array, group by the name, and then map the groups, and reduce each group to a single object using R.mergeWithKey to add the val property. Convert back to an array using R.values, and map to add the static ranks property by name.

Note that you must create a Map or a dictionary object to take the rank by name from.

const { mergeWithKey, pipe, flatten, groupBy, prop, map, reduce, values } = R

const ranks = new Map([['a', 'si'], ['b', 'dp'], ['c', 'en'], ['d', 'fr']])

// merge deep and combine val property values
const combine = mergeWithKey((k, l, r) => k == 'val' ? l + r : r)

const mergeData = pipe(
  flatten, // flatten to a single array
  groupBy(prop('name')), // group by the name
  map(reduce(combine, {})), // combine each group to a single object
  values, // convert back to array
  map(o => ({ ...o, rank: ranks.get(o.name) })), // add the static rank property
)

const data = [[{"name":"a","val":5},{"name":"b","val":10},{"name":"c","val":20},{"name":"d","val":50},{"name":"e","val":100}],[{"name":"a","val":0},{"name":"b","val":20},{"name":"c","val":30},{"name":"d","val":40},{"name":"e","val":10}],[{"name":"a","val":60},{"name":"b","val":50},{"name":"c","val":40},{"name":"d","val":70},{"name":"e","val":30}]]

const results = mergeData(data)

console.log(results)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

Sign up to request clarification or add additional context in comments.

4 Comments

Just one thing, in your solution, you are also returning name: "e" object as well. That is not required
You can always add a filter after flattening to remove unwanted objects.
One thing more, you have used map whereas we can use object there. Is there a specific reason you used map?
Maps are more idiomatic, and the key can be any type of value, but in this case is mostly a personal preference.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.