@extends('template')
@section('title')
Lab 12: Fruitful recursion
@stop
@section('content')
# Lab 12, Part 3: Looping recursion (w/ files)
This section of the lab introduces a new pattern: the use of a loop
within a recursive function. This pattern applies when you need to handle
some kind of sub-objects (which might themselves have more stuff inside)
but you don't know how many there will be. For example, when you're
processing directories that might have other directories in them.
**Open the `looping.py` file provided in the starter files.** You can use
the provided `test_looping.py` to test the functions from this part of
the lab.
## `countDescendants`
Partner A
Partner B
To help you understand this pattern, we've provided a working function
called `countDescendants`, and a global variable `FAMILY` that represents
a family tree. The tree is represented using lists: each person is a list
where the first entry is their name. If that person has descendants, they
are listed as sub-lists within their parent's list. Here's what the `FAMILY` variable looks like:
```py
FAMILY = [
"Louise",
["Richard", ["Sarah"], ["Peter", ["Aaron"]], ["John"], ["Ross"]],
["Steven", ["Chris"], ["Michael", ["Mac"], ["Claire"], ["Frances"]]],
["Jeannie", ["Anna"], ["Claire"]],
]
```
Here is a tree representation of the FAMILY variable:
This variable represents one person, Louise, who has three children, Richard,
Steven, and Jeannie. Richard has four children Sarah, Peter, John, and
Ross, of whom Peter has one child, Aaron. Steven has two children: Chris
(who has no children) and Michael, who has children Mac, Claire, and
Frances. Finally Jeannie has two children, Anna and Claire. In total,
there are 16 people represented, so if we call `countDescendants` on the
whole thing, we should get 16. On the other hand, if we call
`countDescendants` on `FAMILY[1]` (i.e., Richard), we should get 6.
For this part of the lab, to understand how `countDescendants` works,
draw the function call frames for `countDescendants(FAMILY[3])` and then
answer the following questions (click to show the answers after you've
made a guess):
1. How many function call frames are there?
There are a total of 3 function call frames: 1 for Jeannie, and 1 each
for Anna and Claire.
2. What is the "base case" for `countDescendants`?
Although there is no `if/else` like we're used to seeing in a recursive
function, there is still a base case: the function won't make any
recursive calls as long as the `familyTree` list has length 1, because in
that case, the for loop will have an empty sequence and we won't do any
iterations.
Intuitively, the number of recursive calls is equal to the number of
children, so if someone has no children, then they're a base case.
3. What is the result for `countDescendants(FAMILY[3])`?
The result will be 3: 1 for each person.
Now without drawing the full function call frames (but feel free to draw
an abbreviated diagram if it helps), try to answer the following
questions:
4. What is the result for `countDescendants(FAMILY[2])`?
The result will be 6: again it's one for each person.
5. How many function call frames will be created to evaluate `countDescendants(FAMILY[2])`?
Again this is 6, one per person.
6. If each function call frame printed the name of the person it was looking at before the loop, what would be printed for `countDescendants(FAMILY[2])`?
It would print:
```txt
Steven
Chris
Michael
Mac
Claire
Frances
```
7. If each function call frame printed the name of the person it was looking at **after** the loop, what would be printed for `countDescendants(FAMILY[2])`?
It would print:
```txt
Chris
Mac
Claire
Frances
Michael
Steven
```
Note that this is NOT the reverse of the order above. But it is the order
in which each function call frame returns.
## `revealHiddenFiles`
Partner A
Now that you've seen an example of a loop within a recursive function,
it's your turn to write one. Note that **this function will not be
fruitful**. Go to the `revealHiddenFiles` function in the starter file,
and fill in the code. It should print all of the hidden files (files
whose name starts with a '.') in the target directory and any
sub-directories. It should print files and inspect sub-directories in
alphabetical order. The starter file prints an example of what the
correct result should be for the supplied `testdir` folder.
## `listHiddenFiles`
Partner B
Can you make `revealHiddenFiles` fruitful? Go to the `listHiddenFiles`
function in the starter file and write the code for a version of
`revealHiddenFiles` which returns a list of file paths for hidden files
instead of printing them out.
@include('/labs/lab12/_toc')
@stop