Recursion, example of application of the recursion

雨燕双飞 提交于 2021-02-05 06:31:05

问题


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 */ 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))



回答2:


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.



来源:https://stackoverflow.com/questions/60587625/recursion-example-of-application-of-the-recursion

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!