2

I have an array of objects with the following structure that is being sent as response:


    let sampleData = [
      { values: { High: 4, Low: 5,  Medium: 7 } , time: "1571372233234" , sum: 16 },
      { values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},
      { time: "14354545454", sum: 0},
      { time: "14354545454", sum: 0} }
    ];


I need to take each key within each object inside array and form an array out of it. Basically grouping based on the key present in all the objects.If the object has no "values" it should return 0 across the val1,val2,val3.

But the issue , the order of the keys "high,low,medium" inside "values" object in the question is unpredictable. With whatever code I have written keys that are present in the first object will be grouped and follows that order. But I want be it any input order, It should always give me this order "High Medium Low" Order.

The resultant array of objects should look like and should always follow "High Medium Order":

result = [
  { name: 'High', data: [4, 5, 0, 0] }, 
  { name: 'Medium', data: [5, 3, 0, 0] }, 
  { name: 'Low', data: [7, 1, 0, 0] }
]

I have tried the following:

let sampleData = [{ values: { High: 4, Low: 5,  Medium: 7 } , time: "1571372233234" , sum: 16 },{ values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},{ time: "14354545454", sum: 0},{ time: "14354545454", sum: 0 }];
    
const keySet = new Set(sampleData.flatMap(a => Object.keys(a.values || {})));

const merged = sampleData.reduce((acc, {
  values = {}
}) => {
  keySet.forEach(name => {
    acc[name] = acc[name] || {
      name,
      data: []
    };
    acc[name].data.push(values[name] || 0);
  });
  return acc;
}, {});

console.log(merged);

2
  • Why have you tagged your question with ecmascript-5 ? Especially if you are using ES6 syntax Commented Nov 29, 2019 at 13:46
  • I made you a snippet and fixed your sample data (a bracket too many) Commented Nov 29, 2019 at 13:52

3 Answers 3

1

You could take the result set and iterate for the key and array for the value.

let sampleData = [{ values: { High: 4, Low: 5,  Medium: 7 }, time: "1571372233234", sum: 16 }, { values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234", sum: 9 }, { time: "14354545454", sum: 0 }, { time: "14354545454", sum: 0 }],
    keys = ['High', 'Low', 'Medium'],
    grouped = sampleData.reduce((r, { values = {} } = {}) => {
        r.forEach(({ name, data }) => data.push(values[name] || 0));
        return r;
    }, keys.map(name => ({ name, data: [] })));

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

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

5 Comments

order of the keys is guaranteed?
yes, by the result array, as startValue for the reducer.
@Say if your solution is wrapped within a function, that takes sampleData and ["High","Medium","Low"] as parameters
yes, that is possible. you could take the array of keys and build the empty result array first.
I quite did not understand, may be a snippet for understanding would be great
1

You can check for the undefined value when the attr values is not present.

sampleData.reduce((a, {values: {High = 0, Low = 0, Medium = 0} = {}})
                                                               ^
                                                               |
                                                               +-- When attr "values" is 
                                                                   undefined initialize
                                                                   as an "empty" object.

let sampleData = [{ values: { High: 4, Low: 5,  Medium: 7 } , time: "1571372233234" , sum: 16 },{ values: { High: 5, Low: 3, Medium : 1 }, time: "1571372233234" , sum: 9},{ time: "14354545454", sum: 0},{ time: "14354545454", sum: 0}];
    
let result = Object.values(sampleData.reduce((a, {values: {High = 0, Low = 0, Medium = 0} = {}}) => {
  (a["High"] || (a["High"] = {name: "High", data: []})).data.push(High);
  (a["Low"] || (a["Low"] = {name: "Low", data: []})).data.push(Low);
  (a["Medium"] || (a["Medium"] = {name: "Medium", data: []})).data.push(Medium);

  return a;
}, Object.create(null)));
    
 console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

0

You are returning an object and as such the order of the keys is not guaranteed. You probably want an array instead of an object.

You could just construct a final merged object like this

mergedFinal = [ merged['High'], merged['Medium'], merged['Low'] ]

Comments

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.