0

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')
    }
  });
};
1
  • What have you tried so far? Maybe it's just a small error in your logic that we can help identify. Commented Dec 7, 2022 at 19:49

4 Answers 4

1

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);

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

Comments

1

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);

Comments

0

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; }

1 Comment

it doesn't seem to work for a different format? const tree2 = { a: { b: { c: { d: 205103 } } } };
0

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

2 Comments

that doesn't give me the object I need in response though?
the recursive function need to return a value for the previous steps, so instead it gets an empty object and save the result there, should I warp the recursive function with a function that will do that?

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.