2

Ok, tall order I know.

So here's my situation, say I have the array of objects below

var fullData = [{foo1: bar1, foo2: bar2, foo3: bar3}, 
                {foo1: bar4, foo2: bar5, foo3: bar6}, 
                {foo1: bar7, foo2: bar8, foo3: bar6}]

I would like for this to be changed to

[{name: bar1, label: bar1}, {name: bar4, label: bar4},{name: bar7, label: bar7}]

[{name: bar2, label: bar2}, {name: bar5, label: bar5},{name: bar8, label: bar8}]

[{name: bar3, label: bar3}, {name: bar6, label: bar6}]

I have found the below from another thread that splits AoO to an object of Arrays.

var result = res.body.reduce((r, o) => {
                    Object.entries(o).forEach(([k, v]) => (r[k] = r[k] || []).push(v));
                    return r;
                }, Object.create(null));

But it does not filter for duplicates and does not format the data the way I labeled above, and I could not figure out how the function above is working. For duplicates I opted to use the _.uniq from lodash on each individual element of result but was stuck on the 'name' and 'label' formatting, so I thought I would ask much more experienced programmers than myself if there may be a way to incorporate all this into 1 function.

1 Answer 1

1

You can just add check whether the array has the element before pushing it to the array, by changing this:

([k, v]) => (r[k] = r[k] || []).push(v)

to this:

r[k] = r[k] || []
if(!r[k].includes(v)) r[k].push(v)

var fullData = [{foo1: 'bar1', foo2: 'bar2', foo3: 'bar3'}, 
                {foo1: 'bar4', foo2: 'bar5', foo3: 'bar6'}, 
                {foo1: 'bar7', foo2: 'bar8', foo3: 'bar6'}]
                
var result = fullData.reduce((r, o) => {
   Object.entries(o).forEach(([k, v]) => {
      r[k] = r[k] || []
      if(!r[k].includes(v)) r[k].push(v)
   });
   return r;
 }, 
 Object.create(null));

console.log(result)

If you wish to flatten the result to be array of arrays, you can loop through entries of the previous result and push it into the new array

var fullData = [{foo1: 'bar1', foo2: 'bar2', foo3: 'bar3'}, 
                {foo1: 'bar4', foo2: 'bar5', foo3: 'bar6'}, 
                {foo1: 'bar7', foo2: 'bar8', foo3: 'bar6'}]
                
var tmpResult = fullData.reduce((r, o) => {
   Object.entries(o).forEach(([k, v]) => {
      r[k] = r[k] || []
      if(!r[k].includes(v)) r[k].push(v)
   });
   return r;
 }, 
 Object.create(null));

var result = [];
Object.keys(tmpResult).forEach(k => {
  result.push(
    tmpResult[k].map(v => ({name: k, value: v}))
  );
})
console.log(result)

I know that this seems inefficient, but I'm sure this is worth to try.

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

4 Comments

Amazing!! thank you, that already got rid of so much redundant code. Would you also know how to add the 'name' and 'label' before each 'bar' as I mentioned above?
@profiter I already added the code to extract the values as the formatted in your question. If this helps, please kindly give an upvote and accept this answer as well. Thank you.
unfortunately, this now gets rid of the duplication filtering. I had tried something similar and had the same problem. Would you know of another way?
Awesome, thank you that works. I also found another way to make your previous code work, just had to add this line const isFound = r[k].some(element => { if (element.name == v) return true }) and modify your if statement to this if (!isFound) r[k].push({ name: v, label: v }). In any case, your help is greatly appreciated and I will be upvoting and accepting your answer :)

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.