1
00:00:05,170 --> 00:00:10,520
So it's very common to nest one for loop inside another in programming, and we can do the same thing

2
00:00:10,520 --> 00:00:14,400
with comprehensions, and that's called nested comprehensions.

3
00:00:14,420 --> 00:00:19,130
Now the basics are quite straightforward, and as an example, let's see how we can produce a range of

4
00:00:19,130 --> 00:00:21,420
burgers from a few basic ingredients.

5
00:00:21,680 --> 00:00:25,330
So I've created this new file, nested1.py, for this example.

6
00:00:25,520 --> 00:00:29,560
So we're going to have three basic burgers with four different toppings,

7
00:00:29,840 --> 00:00:33,180
and what we'll do is produce a list of the various burgers for sale.

8
00:00:33,430 --> 00:00:42,290
So I'm going to type burgers equals left and right square brackets, and in double quotes beef comma double quotes chicken

9
00:00:43,310 --> 00:00:48,160
comma, and then double quotes, finally spicy bean.

10
00:00:49,410 --> 00:00:56,690
Then we've got our right square bracket. And on the next line, we've got toppings equals left and right square brackets, and

11
00:00:56,690 --> 00:00:59,700
cheese in double quotes comma, egg in double quotes

12
00:00:59,720 --> 00:01:03,190
comma, beans in double quote, double quotes

13
00:01:03,200 --> 00:01:03,740
comma,

14
00:01:03,840 --> 00:01:04,910
and spam in double quotes.

15
00:01:04,920 --> 00:01:12,080
Then we've got our closing square bracket. And the code on line 4, meals equals left and right square

16
00:01:12,080 --> 00:01:25,550
brackets, parentheses burger comma, topping and closing right parentheses, for burger in burgers for topping in toppings.

17
00:01:28,130 --> 00:01:33,150
And then we'll print, on line 5, meals, and 

18
00:01:33,160 --> 00:01:36,050
lets now run that to confirm that it works.

19
00:01:38,100 --> 00:01:45,060
And you can see that we've got each burger type with one of the available toppings, so as an example, beef with cheese

20
00:01:45,090 --> 00:01:48,310
beef with egg, beef with beans, beef with spam and then so on.

21
00:01:48,480 --> 00:01:51,650
It does the same for chicken for each ingredient, and spicy bean as well.

22
00:01:52,660 --> 00:01:56,250
Now the equivalent for loop: lets write that out just so we can see the difference there.

23
00:01:56,630 --> 00:01:59,040
So add on line 7 empty print, to separate

24
00:01:59,050 --> 00:02:00,210
things a bit.

25
00:02:00,590 --> 00:02:06,160
And we're going to put on line 9, for burger in burgers

26
00:02:06,350 --> 00:02:20,320
colon, for topping in toppings colon, and we'll do a print, two parentheses burger comma space topping, and two right parentheses,

27
00:02:20,820 --> 00:02:22,020
and I made a typo there,

28
00:02:22,140 --> 00:02:23,180
burgers

29
00:02:26,660 --> 00:02:28,200
for burger.

30
00:02:28,790 --> 00:02:33,160
OK, so let's run that to confirm that it actually works,

31
00:02:35,320 --> 00:02:37,150
and you can see that we get the same results.

32
00:02:37,160 --> 00:02:40,960
Now I've printed out the burgers in the for loop instead of adding them to another list

33
00:02:40,960 --> 00:02:45,910
but you can see by looking at this list here, we've actually got the same combination of burgers and

34
00:02:45,910 --> 00:02:46,780
toppings

35
00:02:46,780 --> 00:02:53,720
printing out. Now incidentally, we could have modified the comprehension to do the same thing.

36
00:02:53,770 --> 00:02:58,930
It produces a list which we can just iterate over, so we could come back up here to line 4, and do

37
00:02:58,960 --> 00:03:08,200
something like for, for meals, and this time we'll put an in there instead of an equals sign. Then on the end we'll put a colon.

38
00:03:08,910 --> 00:03:14,730
Then on line 5, print parentheses meals.

39
00:03:14,860 --> 00:03:17,830
And what I'll do is change this, so I'll delete that print meals there,

40
00:03:17,850 --> 00:03:19,980
so we've just got line 7 showing like that.

41
00:03:20,290 --> 00:03:21,190
So if we run that,

42
00:03:24,110 --> 00:03:29,070
you can see we've essentially now got exactly the same. So basically as you saw I just added for at the start,

43
00:03:29,070 --> 00:03:32,640
changed the equal to an in, and added a colon to the end.

44
00:03:32,670 --> 00:03:38,040
So after that change, we printed the combinations instead of storing them in a list, and again confirmation

45
00:03:38,040 --> 00:03:41,460
that the program's now printing out exactly the same

46
00:03:41,570 --> 00:03:46,180
output, well is actually showing or outputting exactly the same output twice.

47
00:03:46,190 --> 00:03:52,530
Now if you're going to iterate over a list, and don't intend to use it again, then seriously consider

48
00:03:52,530 --> 00:03:54,840
using a generator expression instead.

49
00:03:54,840 --> 00:03:56,980
Now I'm going to come back to this point shortly,

50
00:03:57,210 --> 00:04:02,760
but for now though, we've created a nested list comprehension that does the same job as the nested for

51
00:04:02,760 --> 00:04:03,750
loops.

52
00:04:03,750 --> 00:04:06,210
Now that's quite a simple example to start with.

53
00:04:06,210 --> 00:04:12,120
We're using existing lists, burgers and toppings, which makes it quite easy to see what's going on. Now we've

54
00:04:12,120 --> 00:04:19,110
used a comprehension to combine two existing lists, to produce another list containing all combinations.

55
00:04:19,110 --> 00:04:22,520
Now, I wouldn't recommend doing that in this case.

56
00:04:22,560 --> 00:04:27,540
The reason, is that we've produced what's called a product of the two lists, and Python actually has a function

57
00:04:27,540 --> 00:04:29,680
to do that in the standard library.

58
00:04:29,680 --> 00:04:30,710
Now I don't want it to digress

59
00:04:30,780 --> 00:04:34,320
at the moment. We're focusing on nested comprehensions at the moment,

60
00:04:34,320 --> 00:04:39,540
so you'll see that in the video after next. But with nested list comprehensions you can write the

61
00:04:39,540 --> 00:04:46,350
comprehensions in a different way, to get different results. And to see what I mean we're going to copy the comprehension

62
00:04:46,740 --> 00:04:51,240
and paste it in after the for loop, then we'll comment out the for loop,

63
00:04:51,570 --> 00:04:59,300
just to keep the output a bit tidier. So I'm going to come up here and copy these two lines, line 4 and 5, then

64
00:04:59,300 --> 00:05:02,250
we're going to comment out lines 9, 10 and 11 for now,

65
00:05:06,070 --> 00:05:09,040
and then what we're going to do is paste in line 13.

66
00:05:09,890 --> 00:05:14,760
And what we're going to do is add some left and right square brackets, so we're going to add the first left one here,

67
00:05:15,590 --> 00:05:19,020
to the left, so for meals in and two left square brackets,

68
00:05:19,020 --> 00:05:25,010
and the other one, I'm going to come down here after burgers, and put the right square bracket there.

69
00:05:28,140 --> 00:05:32,010
Alright so lets try running that.

70
00:05:32,020 --> 00:05:37,570
So by making a slight change to the code on line 13, we've added a bit of structure.

71
00:05:37,600 --> 00:05:41,430
Now if we have a look at the list there we've got a flat list containing tuples, which is our first one

72
00:05:41,430 --> 00:05:42,090
up here,

73
00:05:42,390 --> 00:05:48,290
the beef and cheese, beef and egg and so on, but this next one down here, the second output which was from

74
00:05:48,320 --> 00:05:50,480
the character on line 13 and 14,

75
00:05:50,730 --> 00:05:53,790
that's a nested list containing a list of tuples.

76
00:05:53,820 --> 00:05:58,490
So in both cases the lists contain tuples but the first list holds all the tuples,

77
00:05:58,590 --> 00:06:04,440
whereas the second list that's being output here, is made up of four lists each containing the tuples, and

78
00:06:04,440 --> 00:06:06,300
you can see that as it goes through.

79
00:06:06,640 --> 00:06:10,800
Now I should probably, to make things a bit simpler here, let's just change the names for that, so it's clear,

80
00:06:11,940 --> 00:06:18,950
so in our program, nested meals, nested meals but the concept again is the same, we've just changed the variable name there.

81
00:06:19,290 --> 00:06:21,510
Run it again and we still get the same output as you can.

82
00:06:22,740 --> 00:06:27,330
But that second output, that's not the only way that it differs from the first one. You may have

83
00:06:27,330 --> 00:06:30,140
noticed that the ordering has now changed.

84
00:06:30,450 --> 00:06:35,820
Instead of getting the beef burgers followed by chicken, then all spicy bean, we're now getting all the cheese

85
00:06:35,820 --> 00:06:41,720
toppings, followed by the egg and so on. So from left to right we've got beef cheese, chicken cheese and spicy bean cheese,

86
00:06:41,730 --> 00:06:48,660
and then same for egg, beans and spam, as opposed to the first list which was each burger type, and it's

87
00:06:48,660 --> 00:06:51,390
individual type, available list of toppings.

88
00:06:52,710 --> 00:06:55,510
Now we haven't changed the structure of the final

89
00:06:55,660 --> 00:06:59,240
list. We've just changed the way that the comprehension's executed.

90
00:06:59,250 --> 00:07:02,100
Now that may seem strange because everything's in the same order.

91
00:07:02,280 --> 00:07:05,320
We've still got 'for burger in burgers' in our code here,

92
00:07:08,750 --> 00:07:10,860
followed by 'for toppings in toppings'.

93
00:07:12,440 --> 00:07:16,220
And that's obviously the same for both comprehensions on line 4 and line 13.

94
00:07:16,760 --> 00:07:19,770
So what's actually going on here and why have we got a difference now?

95
00:07:20,060 --> 00:07:26,330
Well the difference is, on line 4, this contains the expression here, burger toppings in parentheses

96
00:07:26,750 --> 00:07:30,880
which is just a tuple, and the rest of the code forms the iteration part.

97
00:07:31,010 --> 00:07:35,190
And we've actually got a double iteration iterating over two different lists.

98
00:07:35,420 --> 00:07:39,370
So this is a comprehension with multiple iteration parts.

99
00:07:39,390 --> 00:07:40,060
So it iterates over

100
00:07:40,160 --> 00:07:41,200
the burgers list, 

101
00:07:41,420 --> 00:07:44,170
then over the toppings list for each burger.

102
00:07:44,170 --> 00:07:46,780
So let's just clarify that.

103
00:07:46,810 --> 00:07:50,390
So we've got a comprehension with two iteration parts.

104
00:07:50,410 --> 00:07:56,750
After getting the first burger, beef, the second iteration part returns each of the toppings in turn,

105
00:07:57,010 --> 00:08:02,770
and once all the toppings have been used, the first iterator, the first iterator part, moves onto the

106
00:08:02,770 --> 00:08:07,480
next burger, chicken. Now the second iterator then runs through all the toppings again,

107
00:08:07,510 --> 00:08:09,760
then we move on to the next burger and so on.

108
00:08:09,760 --> 00:08:16,000
So technically this probably isn't a nested comprehension, rather it's a comprehension with two iterator

109
00:08:16,110 --> 00:08:17,080
parts.

110
00:08:17,530 --> 00:08:22,840
So it produces a flat list as we saw, rather than lists nested inside another list.

111
00:08:22,840 --> 00:08:28,360
Now it's worth noting that the Python docs don't use the term nested comprehension, but you'll see people

112
00:08:28,360 --> 00:08:34,210
referring to both of our comprehension forms as nested comprehensions. Alright so with that said how is

113
00:08:34,210 --> 00:08:41,929
the second one different? Well here we have got a comprehension whose expression is another list comprehension.

114
00:08:42,270 --> 00:08:44,000
Now the outer comprehension

115
00:08:44,080 --> 00:08:49,190
iterates over each item in toppings, then evaluates the expression for each one.

116
00:08:49,210 --> 00:08:55,510
Now the expression is itself a comprehension that iterates over each of the burgers. When written like

117
00:08:55,510 --> 00:09:02,050
this using another comprehension as the expression, the outer iteration values are used first, and that's why

118
00:09:02,050 --> 00:09:05,720
we get the ordering changed.

119
00:09:05,850 --> 00:09:10,470
So don't worry if you struggle to understand or remember this. When you want to create a comprehension

120
00:09:10,570 --> 00:09:14,650
to produce a specific result, you can get there with a bit of trial and error.

121
00:09:15,030 --> 00:09:20,150
But understanding this just cuts out the trial and error, and you can create the correct comprehension

122
00:09:20,220 --> 00:09:21,730
first time.

123
00:09:21,840 --> 00:09:27,750
Now remember that there are different ways to phrase your code, and that you can alter the way a comprehension

124
00:09:27,750 --> 00:09:33,600
works, just as we've done in this example. Now if we wanted our second comprehension to produce

125
00:09:33,600 --> 00:09:38,910
the same ordering as the first one, and the same as the for loop, we just have to swap the two iteration

126
00:09:38,910 --> 00:09:40,170
parts.

127
00:09:40,170 --> 00:09:42,630
So lets just see how that would work.

128
00:09:42,660 --> 00:09:52,960
So I'll just add a print here to separate the output, then on line 18, for nested underscore meals, in two square brackets parentheses,

129
00:09:54,330 --> 00:10:05,800
burger comma topping, right parentheses, for topping in toppings, then one right square bracket.

130
00:10:06,200 --> 00:10:14,010
And then we end with for burger in burgers right square bracket colon.

131
00:10:14,210 --> 00:10:18,210
Then on the next line print nested meals.

132
00:10:18,270 --> 00:10:19,110
So lets run that,

133
00:10:22,030 --> 00:10:28,690
and you can see we've now got the output, beef cheese, beef egg, beef beans, beef spam as opposed to the other example,

134
00:10:28,750 --> 00:10:29,840
where we're getting beef

135
00:10:29,840 --> 00:10:33,350
cheese, chicken cheese, spicy bean cheese and so on all the way through.

136
00:10:33,690 --> 00:10:36,360
So it's basically producing all the beef burger variants,

137
00:10:36,400 --> 00:10:41,450
then the chicken burgers, then finally the spicy bean burgers, just like the original loop did.

138
00:10:41,450 --> 00:10:43,260
Now we have got a different structure though,

139
00:10:43,390 --> 00:10:50,090
a two dimensional array if you like. The main list contains three further lists, one for each of the burger types.

140
00:10:50,110 --> 00:10:57,490
Alright so time for a challenge. Alright, so what I'm going to do is create a new file here, and this will be in the resources section

141
00:10:57,490 --> 00:10:58,270
of the video.

142
00:10:58,600 --> 00:11:04,520
Let's go ahead and create our new one, we'll call it nested challenge,

143
00:11:04,620 --> 00:11:15,610
nested underscore challenge. Then I'm going to paste in the code there, close down the run window, and I'll just read this out to make it clear.

144
00:11:15,630 --> 00:11:21,690
So in an earlier video we used a for loop to print out the times tables for values from 1 to 10.

145
00:11:21,690 --> 00:11:24,840
Now that was a nested loop and that appears below.

146
00:11:24,840 --> 00:11:30,540
Now the challenge here is to use a nested comprehension to produce the same values. Now you can iterate

147
00:11:30,540 --> 00:11:33,280
over the list to produce the same output as the for loop,

148
00:11:33,360 --> 00:11:34,490
or just print out the list,

149
00:11:34,530 --> 00:11:38,090
up to you. And we'll just run this just to confirm the output we're looking for.

150
00:11:39,780 --> 00:11:44,070
So there's the output there. Right so I'll stop the video here.

151
00:11:44,080 --> 00:11:48,100
I'll close down the run window, and we'll go through the solution in the next video.

