0

Could you please suggest any shorter code to solve following problem. I have array of objects:

const arr1=[
  { '1': { grade: 1.3, counter: 2 } },
  { '1': { grade: 2.8, counter: 2 } },
  { '2': { grade: 4.5, counter: 1 } },
  { '2': { grade: 2.4, counter: 1 } }
]

the output should look like:

const obj1={ 
             '1': {grade:4.1,counter:4}
             '2': {grade:6.9,counter:2}
}

here is the code i have tried :

arr1.reduce((acc,e)=> {
  let element = Object.keys(e)
  if(!acc.hasOwnProperty(element)){
    acc[element]={grade:0,counter:0}

  }
  acc[element].grade+= e[element].grade
  acc[element].counter+= e[element].counter
  return acc
}, {})

Thank you

2
  • 1
    You could remove the empty line (or even all white spaces) to create a shorter code. Commented Apr 30, 2022 at 12:45
  • You have to iterate over the keys of said element. Commented Apr 30, 2022 at 13:16

5 Answers 5

1

Your problem here is that Object.keys(e) return an array of keys and not a single key.

If your object will always be the same (with one key) the you can get the key with : let element = Object.keys(e)[0]

I've decomposed the code with 2 main parts.

  • Getting the key of the current item (with const key = Object.keys(current)[0])
  • Checking if the newObject has the key
  • If yes : updating the grade and counter value with the current object
  • If no : adding the current object to the key

const arr1 = [{
    '1': {
      grade: 1.3,
      counter: 2
    }
  },
  {
    '1': {
      grade: 2.8,
      counter: 2
    }
  },
  {
    '2': {
      grade: 4.5,
      counter: 1
    }
  },
  {
    '2': {
      grade: 2.4,
      counter: 1
    }
  }
]

const newObject = arr1.reduce((newObject, current) => {
  const key = Object.keys(current)[0]
  const associatedObject = newObject[key]
  if (associatedObject) {
    associatedObject.grade += current[key].grade
    associatedObject.counter += current[key].counter
  } else {
    newObject[key] = current[key]
  }
  
  return newObject
}, {})

console.log(newObject)

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

Comments

1

I would go for:

arr1.reduce((o,n)=>{
  Object.keys(n).forEach((key)=>{
    if(!o[key]) o[key]={grade:0, counter:0};
    o[key]["grade"] += n[key]["grade"];
    o[key]["counter"] += n[key]["counter"]; 
  });
 return o;
},{});

Step1: reducing over the array, acc = {}

Step2: iterating over every key of the object at the current index

Step3: summing up the according properties

You forgot to iterate over the keys.

Comment: As a pons asinorum I use for array.reduce() the variable names:

  • o meaning old value (=acc=_accumulator)
  • n meaning new value.

Comments

1

Try this

let arr1=[{'1': {grade: 1.3, counter: 2}},{'1': {grade: 2.8, counter: 2}},{'2': {grade: 4.5, counter: 1}},{'2': {grade: 2.4, counter: 1}}];

arr1 = arr1.reduce((acc, obj) => {
    let [k, v] = Object.entries(obj)[0];
    if(!acc.hasOwnProperty(k)) acc[k] = {grade:0,counter:0};
    acc[k].grade += v.grade;
    acc[k].counter += v.counter;
    return acc
}, {});

console.log(arr1)

Comments

0

Object.keys returns an array of strings, so to check here you would probably want the first one:

arr1.reduce((acc, e) => {
  const element = Object.keys(e)[0]; // `[0]` accesses the first key
  if(!acc.hasOwnProperty(element)){
    acc[element]={grade:0,counter:0}
  }
  acc[element].grade+= e[element].grade
  acc[element].counter+= e[element].counter
  return acc
}, {});

Then instead of the if statement you can use the new logical nullish assignment operator:

arr1.reduce((acc, e) => {
  const element = Object.keys(e)[0];
  
  acc[element] ??= { grade: 0, counter: 0 };

  acc[element].grade += e[element].grade;
  acc[element].counter += e[element].counter;
  return acc
}, {});

This is probably as short as I'd go before it starts getting pointless.

Even further; using nullish coalescing and optional chaining:

arr1.reduce((acc, e) => {
  const element = Object.keys(e)[0];
  
  acc[element] = {
    grade: (acc[element]?.grade ?? 0) + e[element].grade,
    counter: (acc[element?.counter ?? 0) + e[element].counter,
  };

  return acc
}, {});

With Object.assign to do it all in one line:

arr1.reduce((acc, e) => {
  const element = Object.keys(e)[0];

  return Object.assign(acc, {
    [element]: {
      grade: (acc[element]?.grade ?? 0) + e[element].grade,
      counter: (acc[element?.counter ?? 0) + e[element].counter,
    },
  });
}, {});

Finally, just for kicks, let's inline the element variable altogether to get this amazing line:

arr1.reduce((acc, e) => Object.assign(acc, {
    [Object.keys(e)[0]]: {
      grade: (acc[Object.keys(e)[0]]?.grade ?? 0) + e[Object.keys(e)[0]].grade,
      counter: (acc[Object.keys(e)[0]]?.counter ?? 0) + e[Object.keys(e)[0]].counter,
    },
}), {});

Comments

0

Another solution is:

const obj1 = arr1.reduce((acc, value) => {
    if(acc[Object.keys(value)[0]]) {
     acc[Object.keys(value)[0]].grade = acc[Object.keys(value)[0]].grade + value[Object.keys(value)[0]].grade;
     acc[Object.keys(value)[0]].counter = acc[Object.keys(value)[0]].counter + value[Object.keys(value)[0]].counter;
    } else {
     acc[Object.keys(value)[0]] = value[Object.keys(value)[0]];
    }
     return acc;    
})

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.