Red Baron
Red Baron

Reputation: 7652

How to recursively loop through an object in javascript and sum all the values?

If this is my object

{
   "a":{
      "a1":5,
      "b":{
         "b1":10,
         "b2":15,
         "c":{
            "c1":15
         }
      }
   }
}

the output I want is:

{a:45 b:40, c: 15}

c => 15
b => 10 + 15 + c
a => 5 + b + c

how do I achieve this? been banging my head against a brick wall all day

so far I've tried:

let constructedTotals = {};
const calculateVals = (vals) => {
  return vals
    .map((val) => {
      if (typeof val === "object" && Object.keys(val).length > 0) {
        return Object.values(val);
      }
      return val;
    })
    .flatMap((x) => x)
    .filter((x) => typeof x === "number")
    .reduce((a, b) => a + b, 0);
};

const constructing = (construct) => {
  return Object.entries(construct).map((entry) => {
    if (typeof entry[1] === "object") {
      constructing(entry[1]);
      constructedTotals = {
        ...constructedTotals,
        [entry[0]]: calculateVals(Object.values(entry[1])),
      };

    } else {
        console.log('here')
    }
  });
};

Upvotes: 0

Views: 201

Answers (4)

codingStarter
codingStarter

Reputation: 364

you can try this:

let obj = {
   "a":{
      "a1":5,
      "b":{
         "b1":10,
         "b2":15,
         "c":{
            "c1":15
         }
      }
   }
}

let recusive = (obj,output)=>{
  if(typeof(obj) == "object"){
    let keys = Object.keys(obj)
    let sum = 0;
    keys.forEach(key => {
        if(typeof(obj[key]) == "object"){
            output[key] = recusive(obj[key],output)
            sum += output[key]
        }
        else
          sum+= obj[key]    
    });
    return sum
  }
  else
    return obj;
}

let warp = (obj) => {
  let output = {};
  recusive(obj, output);
  return output;
}
console.log(warp(obj))

The output will hold the result, it worked for the example you gave, might throw if you give it an object that is build differently

Upvotes: 0

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48620

You could create a reducer function that:

  • Builds an object by key
  • Accumulates the total of the numbered keys for each node, and adds the previous total

const main = () => {
  const result = reduce(tree, (acc, node) => {
    let currKey, prevKey, currVal = 0;  
    for (const prop in node) {
      const [, key] = prop.match(/^(\w)\d$/) ?? [];
      currKey ??= key;
      if (key) currVal += +node[prop];
      prevKey ??= prop.match(/^(\w)$/)?.[1];
    }
    if (currKey) {
      acc[currKey] = (acc[prevKey] ?? 0) + currVal;
    }
  });

  console.log(result); // { "c": 15, "b": 40, "a": 45 }
};

const reduce = (node, visitor) => {
  const result = {};
  traverse(node, visitor, result);
  return result;
};

const traverse = (node, visitor, result) => {
  if (typeof node === 'object') {
    for (const prop in node) {
      traverse(node[prop], visitor, result);
    }
  }
  visitor(result, node);
};

const tree = {
  a: {
    a1: 5,
    b: {
      b1: 10,
      b2: 15,
      c: {
        c1: 15
      }
    }
  }
};

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

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386624

You could handover the parent key and add the total of nested keys.

const
    sum = (object, parent = '') => Object
        .entries(object)
        .reduce((r, [k, v]) => {
            if (v && typeof v === 'object') {
                Object.assign(r, sum(v, k));
                if (parent) r[parent] += r[k];
            } else {
                r[parent] = (r[parent] || 0) + v;
            }
            return r;
        }, {}),
    data = { a: { a1: 5, b: { b1: 10, b2: 15, c: { c1: 15 } } } },
    result = sum(data);

console.log(result);

Upvotes: 1

Anil kumar
Anil kumar

Reputation: 1628

const data = {
    a: {
        a1: 5,
        b: {
            b1: 10,
            b2: 15,
            c: {
                c1: 15,
            },
        },
    },
};
const outputObj = {};
function addValue(data) {
    for (const [key, value] of Object.entries(data)) {
        const outKey = key.at(0);
        outputObj[outKey] ??= 0;
        if (typeof value === "object") addValue(value);
        else for (const svKey in outputObj) outputObj[svKey] += value;
    }
}
addValue(data);
console.log(outputObj);

Upvotes: 1

Related Questions