Alwaysblue
Alwaysblue

Reputation: 11850

Understanding Recursive Traversal , of and reduce Example

I was trying to understand Recursive Transversal.

I stumbled upon this link where they wrote something like this for an example

let company = { // the same object, compressed for brevity
  sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 600 }],
  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)); // 6700

Now, I went and read about reduce and of vaguely and I am unable to connect it with this example

Like as per this article

Inside this callback we get two arguments sum & elem. The sum is the last returned value of the reduce function. For example initially the sum value will be 0 then when the callback runs on the first element it will add the elem to the sum and return that value. On second iteration the sum value will be first elem + 0, on third iteration it will be 0 + first elem + second elem.

Now, that example was with array and this is with object but still I am unable to connect how can current.salary be equal to the salary?

Then I am literally unable to comprehend this line

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

Like I understand he is calling sumSalaries recursively but.. Still make no sense to me?

Can someone please-please explain this in stretch?

Upvotes: 0

Views: 98

Answers (2)

Andy
Andy

Reputation: 63525

Let's step through the code:

1) The function

function sumSalaries(department) {

sumSalaries accepts one argument. Initially this will be an object company, but over successive iterations of the object properties this will be either an array or an object.

2) The condition

  if (Array.isArray(department)) {

We have a condition to be satisfied. If the argument is an array, sum the salary values using reduce. Initially the company object doesn't meet this condition.

The sales array, and both arrays from the department object will meet this condition.

3) reduce

    return department.reduce((prev, current) => prev + current.salary, 0);

reduce accepts an initial value 0 that will always be the first argument in the callback function on each iteration. In this instance it's called prev, but could easily be called acc for "accumulator", or sum, for example. The second argument current is the current element in the array.

Important note: the elements in these arrays are all objects.

So we start with 0 passed in prev and the first array object in current and we add the value found in that object's salary property to zero. This value is passed in as the prev argument on the next iteration. We keep adding to this value until there are no more elements to iterate over, and then the result is returned.

4) If the condition isn't met

  } else {
    let sum = 0;

Both the company object, and the development object match this condition.

5) The iterative function call

    for (let subdep of Object.values(department)) {
      sum += sumSalaries(subdep);
    }
    return sum;
  }
}

On the first iteration we're looping over company. Its values are one array (sales) and another object (development). The array and object get fed back into the function. The array gets reduced and the value added to sum, and the object hits satisfies this condition again and each array (sites, internals) is fed back into the function again and their results are reduced and added to the sum.

And that's it! Hope that helps.

Upvotes: 1

ic3b3rg
ic3b3rg

Reputation: 14927

let subdep of Object.values(department)

This iterates over the values when department is not an array. When sumSalaries is first called with company, we hit this line of code because company is not an array. The values of company are the sales array and the development object - these values are both passed into sumSalaries.

Let's look at a simplified example of how the logic would work with pure number values:

const test = {
  sites: 3800,
  internals: 1300
}

let sum = 0;
for (let aggSalaries of Object.values(test)) {
  sum += aggSalaries;
}
console.log(sum)

5100

I would suggest the code can be simplified to:

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

function sumSalaries(department) {
  return Array.isArray(department)
    ? department.reduce((prev, {salary}) => prev + salary, 0)
    : Object.values(department).reduce((memo, value) => memo + sumSalaries(value), 0);
}

console.log(sumSalaries(company));

Upvotes: 1

Related Questions