3

let company = { 
  sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }],
  development: {
    sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }],
    internals: [{name: 'Jack', salary: 1300}]
  }
};

// The function to do the job
function sumSalaries(department) {
  if (Array.isArray(department)) { // case (1)
    return department.reduce((prev, current) => prev + current.salary, 0); // sum the array
  } else { // case (2)
    let sum = 0;
    for (let subdep of Object.values(department)) {
      sum += sumSalaries(subdep); // recursively call for subdepartments, sum the results
    }
    return sum;
  }
}

alert(sumSalaries(company)); // 7700
This code is about using recursion in calculation of total salary in company's departments. Please, explain to me this. In the example of tutorial, recursive traversals, after running the first case (we calculate the salary in sales department) function return this salary. So why it proceed further and calculate another case (development department) if we have return statement in first calculation? Shouldn't it break the flow? And how it sum the case 1 and total sum of case 2?

1
  • 1
    It doesn't continue if the first case runs. But the first time you call it you don't pass it and array, you pass it company which is not an array. So the first time you call it it runs the second case, not the first case Commented Mar 8, 2020 at 15:33

2 Answers 2

2
/*  1 */ function sumSalaries(department) {
/*  2 */ if (Array.isArray(department)) { // case (1)
/*  3 */     return department.reduce((prev, current) => prev + current.salary, 0); // sum the array
/*  4 */   } else { // case (2)
/*  5 */     let sum = 0;
/*  6 */     for (let subdep of Object.values(department)) {
/*  7 */       sum += sumSalaries(subdep); // recursively call for subdepartments, sum the results
/*  8 */     }
/*  9 */     return sum;
/* 10 */   }
/* 11 */ }
/*  (1) */ sumSalaries (company) {
/*  (2) */   Array .isArray (company) //=> false, so hit branch 2
/*  (5) */     sum = 0
/*  (6) */     Object .values (company) //=> [<sales>, <development>]
/*  (6) */     [<sales>, <development>] .for Each ... 
/*  (7) */       sumSalaries (<sales>) {
/*  (2) */         Array .isArray (<sales>) //=> true, so hit branch 1           //       John   Alice
/*  (3) */           <sales>.reduce((prev, current) => prev + current.salary, 0) //=> 0 + 1000 + 1600 = 2600
/*  (3) */           return 2600
/* (10) */       }
/*  (7) */       sum = 0 + 2600 = 2600
/*  (7) */       sumSalaries (<development>) {
/*  (2) */         Array.isArray (<development) //=> false, so hit branch 2
/*  (5) */           sum = 0  // (different instance of `sum` from above)
/*  (6) */           Object.values (<development>) //=> [<sites>, <internal>]
/*  (6) */           [<sites>, <internal>] .for Each ...  
/*  (7) */             sumSalaries (<sites>) {
/*  (2) */               Array.isArray (<sites>) //=> true, so hit branch 1            //       Peter  Alex
/*  (3) */                 <sites>.reduce((prev, current) => prev + current.salary, 0) //=> 0 + 2000 + 1800 = 3800
/*  (3) */                 return 3800
/* (10) */             }
/*  (7) */             sum = 0 + 3800
/*  (7) */             sumSalaries (<internals>) {
/*  (2) */               Array.isArray (<internals>) //=> true, so hit branch 1               Jack
/*  (3) */                 <internals>.reduce((prev, current) => prev + current.salary, 0) //=> 0 + 1300 = 1300
/* (10) */                 return 1300
/* (10) */             }
/*  (7) */             sum = 3800 + 1300 = 5100
/*  (9) */           return 5100
/* (10) */       }
/*  (7) */       sum = 2600 + 5100 = 7700  // (back to the original `sum`)
/*  (9) */       return 7700
/* (11) */ }

But there is something odd about that code. First, it uses reduce to total the values in one case and sum = 0 ... for (...) { sum += ... } ... return sum for the other; that feels odd. Second, it uses a substantially different variable name for the internal variable you're going to supply as a parameter to the recursive call. But the data structure does not suggest that; the company is structured the same as any department or sub-department. This distinction between "department" and "subdep" makes it more difficult to get a feeling for the recursive nature of the problem. Usually, when I need two different names for the data structure, I try to make the names seem aligned. I might, for instance, use the abbreviation dept instead of subdep.

So, I would write this differently. Here's a different version, using a helper function which sums an array of numbers. While it looks quite different, the underlying logic is entirely the same:

const sum = (ns) => ns .reduce ((t, n) => t + n, 0)

const sumSalaries = (department) =>
  Array .isArray (department) 
    ? sum (department .map (empl => empl .salary))
    : sum (Object .values (department) .map (sumSalaries))

const company = {sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }], development: {sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }], internals: [{name: 'Jack', salary: 1300}]}}

console .log (sumSalaries (company))

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

3 Comments

Why I'm so dumb!!??? After 14 days I've returned to this code in order to refresh it in memory and for better understanding, but now I'm instead confused about this part: Why we take values(Object.values(department)), and not keys by logic(Object.keys(department))? We need sales, sites... and so on, and that are keys, not values. And why it doesn't working (Object.keys(department)) What am I missing?
@Roman: There are two properties in company. The first one has key "sales" and value [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }. It's that value which has the salaries you need for your summation. The fact that it's called "sales" had nothing to do with totaling up the salaries.
@ Scott Sauyet Oh, I see, I just didn't see that actually we were working with values, not their keys (their names misled me). Thank's a lot!!!)))
0

It is because the line sum += sumSalaries(subdep) creates a bunch of function calls and each of them are independent.

Let's break the loop into single function calls

for (let subdep of Object.values(department)) {
   sum += sumSalaries(subdep); // recursively call for subdepartments, sum the results
}

is merely

sum += sumSalaries(department.sales);
sum += sumSalaries(department.development);

Each of the function call above will execute on its own and return the value. So, when the first call returns something, it just finishes its own function, not the root function.

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.