Книга: Practical Programming, Fourth Edition
Назад: Processing Lists Using Indices
Дальше: Looping Until a Condition Is Reache d

Nesting Loops in Loops

The body of a loop can contain another loop. In this code, the inner loop is executed once for each item in the outer list:

 >>>​​ ​​outer​​ ​​=​​ ​​[​​'Li'​​,​​ ​​'Na'​​,​​ ​​'K'​​]
 >>>​​ ​​inner​​ ​​=​​ ​​[​​'F'​​,​​ ​​'Cl'​​,​​ ​​'Br'​​]
 >>>​​ ​​for​​ ​​metal​​ ​​in​​ ​​outer:
 ...​​ ​​for​​ ​​halogen​​ ​​in​​ ​​inner:
 ...​​ ​​print(metal​​ ​​+​​ ​​halogen)
 ...
 LiF
 LiCl
 LiBr
 NaF
 NaCl
 NaBr
 KF
 KCl
 KBr

The number of times that function print is called is len(outer) * len(inner). The following table shows that for each iteration of the outer loop (in other words, for each item in outer), the inner loop executes three times (once for each item in inner).

Iteration of
Outer Loop

What metal
Refers To

Iteration of
Inner Loop

What halogen
Refers To

What Is Printed

1st

outer[0]

1st

inner[0]

LiF

2nd

inner[1]

LiCl

3rd

inner[2]

LiBr

2nd

outer[1]

1st

inner[0]

NaF

2nd

inner[1]

NaCl

3rd

inner[2]

NaBr

3rd

outer[2]

1st

inner[0]

KF

2nd

inner[1]

KCl

3rd

inner[2]

KBr

Loops and conditionals can be nested inside one another

Sometimes an inner loop uses the same list as the outer loop. An example of this is shown in a function used to generate a multiplication table. After printing the header row, use a nested loop to print each row of the table in turn, using tabs (see Table 2, ) to align the columns:

 def​ ​print_table​(n: int) -> None:
 """Print the multiplication table for numbers 1 through n inclusive.
 
  >>> print_table(5)
  1 2 3 4 5
  1 1 2 3 4 5
  2 2 4 6 8 10
  3 3 6 9 12 15
  4 4 8 12 16 20
  5 5 10 15 20 25
  """
 # The numbers to include in the table.
  numbers = range(1, n + 1)
 
 # Print the header row.
 for​ i ​in​ numbers:
 print​(f​'​​\t​​{i}'​, end=​''​)
 
 # End the header row.
 print​()
 
 # Print each row number and the contents of each row.
for​ i ​in​ numbers:
print​ (i, end=​''​)
for​ j ​in​ numbers:
print​(f​'​​\t​​{i * j}'​, end=​''​)
 
 # End the current row.
print​()

Each iteration of the outer loop prints a row. Each row consists of a row number, n tab-number pairs, and a newline. It’s the inner loop’s job to print the tabs and numbers part of the row. For print_table(5), let’s take a closer look at what happens during the third iteration of the outer loop:

i is assigned 3, the third item of numbers.

The row number, 3, is printed.

This line of code is the inner loop header, and it will be executed five times. Before the first iteration of the inner loop, j is assigned 1; before the second iteration, it is assigned 2; and so on, until it is assigned 5 before the last iteration.

Five times this line is executed right after the previous line, using whatever value j was just assigned. The first time it prints a tab followed by 3, then a tab followed by 6, and so on until it prints a tab followed by 15.

Now that a row has been printed, the program prints a newline. This line of code is executed outside of the inner loop, ensuring it is executed only once per row.

Looping Over Nested Lists

In addition to looping over lists of numbers, strings, and Booleans, you can also loop over lists of lists. Here is an example of a loop over an outer list. The loop variable, which we’ve named inner_list, is assigned an item of nested list elements at the beginning of each iteration:

 >>>​​ ​​elements​​ ​​=​​ ​​[[​​'Li'​​,​​ ​​'Na'​​,​​ ​​'K'​​],​​ ​​[​​'F'​​,​​ ​​'Cl'​​,​​ ​​'Br'​​]]
 >>>​​ ​​for​​ ​​inner_list​​ ​​in​​ ​​elements:
 ...​​ ​​print(inner_list)
 ...
 ['Li', 'Na', 'K']
 ['F', 'Cl', 'Br']

To access each string in the inner lists, you can loop over the outer list and then over each inner list using a nested loop. Here, Python prints every string in every inner list:

 >>>​​ ​​elements​​ ​​=​​ ​​[[​​'Li'​​,​​ ​​'Na'​​,​​ ​​'K'​​],​​ ​​[​​'F'​​,​​ ​​'Cl'​​,​​ ​​'Br'​​]]
 >>>​​ ​​for​​ ​​inner_list​​ ​​in​​ ​​elements:
 ...​​ ​​for​​ ​​item​​ ​​in​​ ​​inner_list:
 ...​​ ​​print(item)
 ...
 Li
 Na
 K
 F
 Cl
 Br

In the previous code, the outer loop variable, inner_list, refers to a list of strings, and the inner loop variable, item, refers to a string from that list.

When you have a nested list, and you want to do something with every item in the inner lists, you need to use a nested loop.

Looping Over Ragged Lists

Nothing says that nested lists have to be the same length:

 >>>​​ ​​info​​ ​​=​​ ​​[[​​'Isaac Newton'​​,​​ ​​1643,​​ ​​1727],
 ...​​ ​​[​​'Charles Darwin'​​,​​ ​​1809,​​ ​​1882],
 ...​​ ​​[​​'Alan Turing'​​,​​ ​​1912,​​ ​​1954,​​ ​​'[email protected]'​​]]
 >>>​​ ​​for​​ ​​item​​ ​​in​​ ​​info:
 ...​​ ​​print(len(item))
 ...
 3
 3
 4

Nested lists with inner lists of varying lengths are referred to as ragged lists. Ragged lists can be challenging to process if the data isn’t uniform; for example, trying to assemble a list of email addresses from data where some addresses are missing requires careful consideration.

Ragged data does arise normally. For instance, if a daily record is made of the time at which a person has a drink of water, each day will have a different number of entries:

 >>>​​ ​​drinking_times_by_day​​ ​​=​​ ​​[[​​"9:02"​​,​​ ​​"10:17"​​,​​ ​​"13:52"​​,​​ ​​"18:23"​​,​​ ​​"21:31"​​],
 ...​​ ​​[​​"8:45"​​,​​ ​​"12:44"​​,​​ ​​"14:52"​​,​​ ​​"22:17"​​],
 ...​​ ​​[​​"8:55"​​,​​ ​​"11:11"​​,​​ ​​"12:34"​​,​​ ​​"13:46"​​,
 ...​​ ​​"15:52"​​,​​ ​​"17:08"​​,​​ ​​"21:15"​​],
 ...​​ ​​[​​"9:15"​​,​​ ​​"11:44"​​,​​ ​​"16:28"​​],
 ...​​ ​​[​​"10:01"​​,​​ ​​"13:33"​​,​​ ​​"16:45"​​,​​ ​​"19:00"​​],
 ...​​ ​​[​​"9:01"​​,​​ ​​"12:24"​​,​​ ​​"18:51"​​,​​ ​​"23:13"​​]]
 >>>​​ ​​for​​ ​​day​​ ​​in​​ ​​drinking_times_by_day:
 ...​​ ​​for​​ ​​drinking_time​​ ​​in​​ ​​day:
 ...​​ ​​print(drinking_time,​​ ​​end=​​' '​​)
 ...​​ ​​print()
 ...
 9:02 10:17 13:52 18:23 21:31
 8:45 12:44 14:52 22:17
 8:55 11:11 12:34 13:46 15:52 17:08 21:15
 9:15 11:44 16:28
 10:01 13:33 16:45 19:00
 9:01 12:24 18:51 23:13

The inner loop iterates over the items of day, and the length of that list varies.

Назад: Processing Lists Using Indices
Дальше: Looping Until a Condition Is Reache d