As byNation is passed as a variable into outerRollup it’s also available within the innerRollup, correct?

Exactly, yes.

How is the value of byNation specified as the variable for the outerRollup?

That’s just how `d3.rollup`

is defined. To get a bit more insight into that, lets consider how `d3.rollup`

is implemented. The actual source code of it is a bit intense, but here is a version that for the purposes of this discussion is the close enough:

```
function toyRollup(array, rollupFunction, keyFunction) {
// Separate all the values of arrays into groups, based on the keyFunction
let groups = new Map();
for (let element of array) {
let key = keyFunction(element);
if (!groups.has(key)) {
groups.set(key, []);
}
groups.get(key).push(element);
}
// For each group, use the rollupFunction to combine it into a single value
let rolledUpData = new Map();
for (let [key, group] of groups.entries()) {
let combinedValue = rollupFunction(group);
rolledUpData.set(key, combinedValue);
}
return rolledUpData;
}
```

If we then consider just a one layered version of the problem where we just want to calculate the number of athletes in each nation:

```
function rollupFunction(athletesOfOneNation) {
return athletesOfOneNation.length;
}
function keyFunction(athlete) {
return athelete.nation;
}
let numberOfAthletesInEachNation = toyRollup(athletes, rollupFunction, keyFunction);
```

then we can substitute the value into the definition of `toyRollup`

. This is what the solution to the question about the number of athletes in each nation would look like without d3.rollup:

```
function calculateNumberOfAthletesInEachNation(athletes) {
let athletesGroupedByNation = new Map();
for (let athlete of athletes) {
let key = athlete.nation;
if (!athletesGroupedByNation.has(key)) {
athletesGroupedByNation.set(key, []);
}
athletesGroupedByNation.get(key).push(athlete);
}
let numberOfAthletesByNation = new Map();
for (let [nation, group] of athletesGroupedByNation.entries()) {
numberOfAthletesByNation.set(nation, group.length);
}
return numberOfAthletes;
}
```

Hopefully that helps make sense of how the data moves around during the rollup process! I also hope that now you can see the appeal of having an API that can turn that complicated function into something as compact as this:

```
const numAthletesByNation = d3.rollup(athletes, ds => ds.length, d => d.nation);
```