forked from swcarpentry/python-novice-inflammation
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy path03-lists.html
277 lines (270 loc) · 23.6 KB
/
03-lists.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<title>Software Carpentry: Programming with Python</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap-theme.css" />
<link rel="stylesheet" type="text/css" href="css/swc.css" />
<link rel="alternate" type="application/rss+xml" title="Software Carpentry Blog" href="http://software-carpentry.org/feed.xml"/>
<meta charset="UTF-8" />
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body class="lesson">
<div class="container card">
<div class="banner">
<a href="http://software-carpentry.org" title="Software Carpentry">
<img alt="Software Carpentry banner" src="img/software-carpentry-banner.png" />
</a>
</div>
<article>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<a href="index.html"><h1 class="title">Programming with Python</h1></a>
<h2 class="subtitle">Storing Multiple Values in Lists</h2>
<section class="objectives panel panel-warning">
<div class="panel-heading">
<h2 id="learning-objectives"><span class="glyphicon glyphicon-certificate"></span>Learning Objectives</h2>
</div>
<div class="panel-body">
<ul>
<li>Explain what a list is.</li>
<li>Create and index lists of simple values.</li>
</ul>
</div>
</section>
<p>Just as a <code>for</code> loop is a way to do operations many times, a list is a way to store many values. Unlike NumPy arrays, lists are built into the language (so we don’t have to load a library to use them). We create a list by putting values inside square brackets:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">odds <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">5</span>, <span class="dv">7</span>]
<span class="bu">print</span>(<span class="st">'odds are:'</span>, odds)</code></pre></div>
<pre class="output"><code>odds are: [1, 3, 5, 7]</code></pre>
<p>We select individual elements from lists by indexing them:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="bu">print</span>(<span class="st">'first and last:'</span>, odds[<span class="dv">0</span>], odds[<span class="op">-</span><span class="dv">1</span>])</code></pre></div>
<pre class="output"><code>first and last: 1 7</code></pre>
<p>and if we loop over a list, the loop variable is assigned elements one at a time:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="cf">for</span> number <span class="op">in</span> odds:
<span class="bu">print</span>(number)</code></pre></div>
<pre class="output"><code>1
3
5
7</code></pre>
<p>There is one important difference between lists and strings: we can change the values in a list, but we cannot change the characters in a string. For example:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">names <span class="op">=</span> [<span class="st">'Newton'</span>, <span class="st">'Darwing'</span>, <span class="st">'Turing'</span>] <span class="co"># typo in Darwin's name</span>
<span class="bu">print</span>(<span class="st">'names is originally:'</span>, names)
names[<span class="dv">1</span>] <span class="op">=</span> <span class="st">'Darwin'</span> <span class="co"># correct the name</span>
<span class="bu">print</span>(<span class="st">'final value of names:'</span>, names)</code></pre></div>
<pre class="output"><code>names is originally: ['Newton', 'Darwing', 'Turing']
final value of names: ['Newton', 'Darwin', 'Turing']</code></pre>
<p>works, but:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">name <span class="op">=</span> <span class="st">'Bell'</span>
name[<span class="dv">0</span>] <span class="op">=</span> <span class="st">'b'</span></code></pre></div>
<pre class="error"><code>---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-220df48aeb2e> in <module>()
1 name = 'Bell'
----> 2 name[0] = 'b'
TypeError: 'str' object does not support item assignment</code></pre>
<p>does not.</p>
<aside class="callout panel panel-info">
<div class="panel-heading">
<h2 id="ch-ch-ch-changes"><span class="glyphicon glyphicon-pushpin"></span>Ch-Ch-Ch-Changes</h2>
</div>
<div class="panel-body">
<p>Data which can be modified in place is called <a href="reference.html#mutable">mutable</a>, while data which cannot be modified is called <a href="reference.html#immutable">immutable</a>. Strings and numbers are immutable. This does not mean that variables with string or number values are constants, but when we want to change the value of a string or number variable, we can only replace the old value with a completely new value.</p>
<p>Lists and arrays, on the other hand, are mutable: we can modify them after they have been created. We can change individual elements, append new elements, or reorder the whole list. For some operations, like sorting, we can choose whether to use a function that modifies the data in place or a function that returns a modified copy and leaves the original unchanged.</p>
<p>Be careful when modifying data in place. If two variables refer to the same list, and you modify the list value, it will change for both variables! If you want variables with mutable values to be independent, you must make a copy of the value when you assign it.</p>
<p>Because of pitfalls like this, code which modifies data in place can be more difficult to understand. However, it is often far more efficient to modify a large data structure in place than to create a modified copy for every small change. You should consider both of these aspects when writing your code.</p>
</div>
</aside>
<aside class="callout panel panel-info">
<div class="panel-heading">
<h2 id="nested-lists"><span class="glyphicon glyphicon-pushpin"></span>Nested Lists</h2>
</div>
<div class="panel-body">
<p>Since lists can contain any Python variable, it can even contain other lists.</p>
<p>For example, we could represent the products in the shelves of a small grocery shop:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">x <span class="op">=</span> [[<span class="st">'pepper'</span>, <span class="st">'zucchini'</span>, <span class="st">'onion'</span>],
[<span class="st">'cabbage'</span>, <span class="st">'lettuce'</span>, <span class="st">'garlic'</span>],
[<span class="st">'apple'</span>, <span class="st">'pear'</span>, <span class="st">'banana'</span>]]</code></pre></div>
<p>Here is a visual example of how indexing a list of lists <code>x</code> works:</p>
<p><a href='https://twitter.com/hadleywickham/status/643381054758363136'> <img src="img/indexing_lists_python.png" alt="The first element of a list. Adapted from @hadleywickham’s tweet about R > lists." /></a></p>
<p>Using the previously declared list <code>x</code>, these would be the results of the index operations shown in the image:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="bu">print</span>([x[<span class="dv">0</span>]])</code></pre></div>
<pre class="output"><code>[['pepper', 'zucchini', 'onion']]</code></pre>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="bu">print</span>(x[<span class="dv">0</span>])</code></pre></div>
<pre class="output"><code>['pepper', 'zucchini', 'onion']</code></pre>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="bu">print</span>(x[<span class="dv">0</span>][<span class="dv">0</span>])</code></pre></div>
<pre class="output"><code>'pepper'</code></pre>
<p>Thanks to <a href="https://twitter.com/hadleywickham/status/643381054758363136">Hadley Wickham</a> for the image above.</p>
</div>
</aside>
<p>There are many ways to change the contents of lists besides assigning new values to individual elements:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">odds.append(<span class="dv">11</span>)
<span class="bu">print</span>(<span class="st">'odds after adding a value:'</span>, odds)</code></pre></div>
<pre class="output"><code>odds after adding a value: [1, 3, 5, 7, 11]</code></pre>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python"><span class="kw">del</span> odds[<span class="dv">0</span>]
<span class="bu">print</span>(<span class="st">'odds after removing the first element:'</span>, odds)</code></pre></div>
<pre class="output"><code>odds after removing the first element: [3, 5, 7, 11]</code></pre>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">odds.reverse()
<span class="bu">print</span>(<span class="st">'odds after reversing:'</span>, odds)</code></pre></div>
<pre class="output"><code>odds after reversing: [11, 7, 5, 3]</code></pre>
<p>While modifying in place, it is useful to remember that Python treats lists in a slightly counterintuitive way.</p>
<p>If we make a list and (attempt to) copy it then modify in place, we can cause all sorts of trouble:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">odds <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">5</span>, <span class="dv">7</span>]
primes <span class="op">=</span> odds
primes <span class="op">+=</span> [<span class="dv">2</span>]
<span class="bu">print</span>(<span class="st">'primes:'</span>, primes)
<span class="bu">print</span>(<span class="st">'odds:'</span>, odds)</code></pre></div>
<pre class="output"><code>primes: [1, 3, 5, 7, 2]
odds: [1, 3, 5, 7, 2]</code></pre>
<p>This is because Python stores a list in memory, and then can use multiple names to refer to the same list. If all we want to do is copy a (simple) list, we can use the <code>list</code> function, so we do not modify a list we did not mean to:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">odds <span class="op">=</span> [<span class="dv">1</span>, <span class="dv">3</span>, <span class="dv">5</span>, <span class="dv">7</span>]
primes <span class="op">=</span> <span class="bu">list</span>(odds)
primes <span class="op">+=</span> [<span class="dv">2</span>]
<span class="bu">print</span>(<span class="st">'primes:'</span>, primes)
<span class="bu">print</span>(<span class="st">'odds:'</span>, odds)</code></pre></div>
<pre class="output"><code>primes: [1, 3, 5, 7, 2]
odds: [1, 3, 5, 7]</code></pre>
<p>This is different from how variables worked in lesson 1, and more similar to how a spreadsheet works.</p>
<section class="challenge panel panel-success">
<div class="panel-heading">
<h2 id="turn-a-string-into-a-list"><span class="glyphicon glyphicon-pencil"></span>Turn a string into a list</h2>
</div>
<div class="panel-body">
<p>Use a for-loop to convert the string “hello” into a list of letters:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">[<span class="st">"h"</span>, <span class="st">"e"</span>, <span class="st">"l"</span>, <span class="st">"l"</span>, <span class="st">"o"</span>]</code></pre></div>
<p>Hint: You can create an empty list like this:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">my_list <span class="op">=</span> []</code></pre></div>
</div>
</section>
<p>Subsets of lists and strings can be accessed by specifying ranges of values in brackets, similar to how we accessed ranges of positions in a Numpy array. This is commonly referred to as “slicing” the list/string.</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">binomial_name <span class="op">=</span> <span class="st">"Drosophila melanogaster"</span>
group <span class="op">=</span> binomial_name[<span class="dv">0</span>:<span class="dv">10</span>]
<span class="bu">print</span>(<span class="st">"group:"</span>, group)
species <span class="op">=</span> binomial_name[<span class="dv">11</span>:<span class="dv">24</span>]
<span class="bu">print</span>(<span class="st">"species:"</span>, species)
chromosomes <span class="op">=</span> [<span class="st">"X"</span>, <span class="st">"Y"</span>, <span class="st">"2"</span>, <span class="st">"3"</span>, <span class="st">"4"</span>]
autosomes <span class="op">=</span> chromosomes[<span class="dv">2</span>:<span class="dv">5</span>]
<span class="bu">print</span>(<span class="st">"autosomes:"</span>, autosomes)
last <span class="op">=</span> chromosomes[<span class="op">-</span><span class="dv">1</span>]
<span class="bu">print</span>(<span class="st">"last:"</span>, last)</code></pre></div>
<pre class="output"><code>group: Drosophila
species: melanogaster
autosomes: ["2", "3", "4"]
last: 4</code></pre>
<section class="challenge panel panel-success">
<div class="panel-heading">
<h2 id="slicing-from-the-end"><span class="glyphicon glyphicon-pencil"></span>Slicing from the end</h2>
</div>
<div class="panel-body">
<p>Use slicing to access only the last four characters of a string or entries of a list.</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">string_for_slicing <span class="op">=</span> <span class="st">"Observation date: 02-Feb-2013"</span>
list_for_slicing <span class="op">=</span> [[<span class="st">"fluorine"</span>, <span class="st">"F"</span>], [<span class="st">"chlorine"</span>, <span class="st">"Cl"</span>], [<span class="st">"bromine"</span>, <span class="st">"Br"</span>], [<span class="st">"iodine"</span>, <span class="st">"I"</span>], [<span class="st">"astatine"</span>, <span class="st">"At"</span>]]</code></pre></div>
<pre class="output"><code>"2013"
[["chlorine", "Cl"], ["bromine", "Br"], ["iodine", "I"], ["astatine", "At"]]</code></pre>
<p>Would your solution work regardless of whether you knew beforehand the length of the string or list (e.g. if you wanted to apply the solution to a set of lists of different lengths)? If not, try to change your approach to make it more robust.</p>
</div>
</section>
<section class="challenge panel panel-success">
<div class="panel-heading">
<h2 id="non-continuous-slices"><span class="glyphicon glyphicon-pencil"></span>Non-continuous slices</h2>
</div>
<div class="panel-body">
<p>So far we’ve seen how to use slicing to take single blocks of successive entries from a sequence. But what if we want to take a subset of entries that aren’t next to each other in the sequence?</p>
<p>You can achieve this by providing a third argument to the range within the brackets, called the <em>step size</em>. The example below shows how you can take every third entry in a list:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">primes <span class="op">=</span> [<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">5</span>, <span class="dv">7</span>, <span class="dv">11</span>, <span class="dv">13</span>, <span class="dv">17</span>, <span class="dv">19</span>, <span class="dv">23</span>, <span class="dv">29</span>, <span class="dv">31</span>, <span class="dv">37</span>]
subset <span class="op">=</span> primes[<span class="dv">0</span>:<span class="dv">12</span>:<span class="dv">3</span>]
<span class="bu">print</span>(<span class="st">"subset"</span>, subset)</code></pre></div>
<pre class="output"><code>subset [2, 7, 17, 29]</code></pre>
<p>Notice that the slice taken begins with the first entry in the range, followed by entries taken at equally-spaced intervals (the steps) thereafter. If you wanted to begin the subset with the third entry, you would need to specify that as the starting point of the sliced range:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">primes <span class="op">=</span> [<span class="dv">2</span>, <span class="dv">3</span>, <span class="dv">5</span>, <span class="dv">7</span>, <span class="dv">11</span>, <span class="dv">13</span>, <span class="dv">17</span>, <span class="dv">19</span>, <span class="dv">23</span>, <span class="dv">29</span>, <span class="dv">31</span>, <span class="dv">37</span>]
subset <span class="op">=</span> primes[<span class="dv">2</span>:<span class="dv">12</span>:<span class="dv">3</span>]
<span class="bu">print</span>(<span class="st">"subset"</span>, subset)</code></pre></div>
<pre class="output"><code>subset [5, 13, 23, 37]</code></pre>
<p>Use the step size argument to create a new string that contains only every other character in the string “In an octopus’s garden in the shade”</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">beatles <span class="op">=</span> <span class="st">"In an octopus's garden in the shade"</span></code></pre></div>
<pre class="output"><code>I notpssgre ntesae</code></pre>
</div>
</section>
<p>If you want to take a slice from the beginning of a sequence, you can omit the first index in the range:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">date <span class="op">=</span> <span class="st">"Monday 4 January 2016"</span>
day <span class="op">=</span> date[<span class="dv">0</span>:<span class="dv">6</span>]
<span class="bu">print</span>(<span class="st">"Using 0 to begin range:"</span>, day)
day <span class="op">=</span> date[:<span class="dv">6</span>]
<span class="bu">print</span>(<span class="st">"Omitting beginning index:"</span>, day)</code></pre></div>
<pre class="output"><code>Using 0 to begin range: Monday
Omitting beginning index: Monday</code></pre>
<p>And equally, you can omit the ending index in the range to take a slice to the very end of the sequence:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">months <span class="op">=</span> [<span class="st">"jan"</span>, <span class="st">"feb"</span>, <span class="st">"mar"</span>, <span class="st">"apr"</span>, <span class="st">"may"</span>, <span class="st">"jun"</span>, <span class="st">"jul"</span>, <span class="st">"aug"</span>, <span class="st">"sep"</span>, <span class="st">"oct"</span>, <span class="st">"nov"</span>, <span class="st">"dec"</span>]
sond <span class="op">=</span> months[<span class="dv">8</span>:<span class="dv">12</span>]
<span class="bu">print</span>(<span class="st">"With known last position:"</span>, sond)
sond <span class="op">=</span> months[<span class="dv">8</span>:<span class="bu">len</span>(months)]
<span class="bu">print</span>(<span class="st">"Using len() to get last entry:"</span>, sond)
sond <span class="op">=</span> months[<span class="dv">8</span>:]
(<span class="st">"Omitting ending index:"</span>, sond)</code></pre></div>
<pre class="output"><code>With known last position: ["sep", "oct", "nov", "dec"]
Using len() to get last entry: ["sep", "oct", "nov", "dec"]
Omitting ending index: ["sep", "oct", "nov", "dec"]</code></pre>
<section class="challenge panel panel-success">
<div class="panel-heading">
<h2 id="tuples-and-exchanges"><span class="glyphicon glyphicon-pencil"></span>Tuples and exchanges</h2>
</div>
<div class="panel-body">
<p>Explain what the overall effect of this code is:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">left <span class="op">=</span> <span class="st">'L'</span>
right <span class="op">=</span> <span class="st">'R'</span>
temp <span class="op">=</span> left
left <span class="op">=</span> right
right <span class="op">=</span> temp</code></pre></div>
<p>Compare it to:</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">left, right <span class="op">=</span> right, left</code></pre></div>
<p>Do they always do the same thing? Which do you find easier to read?</p>
</div>
</section>
<section class="challenge panel panel-success">
<div class="panel-heading">
<h2 id="overloading"><span class="glyphicon glyphicon-pencil"></span>Overloading</h2>
</div>
<div class="panel-body">
<p><code>+</code> usually means addition, but when used on strings or lists, it means “concatenate”. Given that, what do you think the multiplication operator <code>*</code> does on lists? In particular, what will be the output of the following code?</p>
<div class="sourceCode"><pre class="sourceCode python"><code class="sourceCode python">counts <span class="op">=</span> [<span class="dv">2</span>, <span class="dv">4</span>, <span class="dv">6</span>, <span class="dv">8</span>, <span class="dv">10</span>]
repeats <span class="op">=</span> counts <span class="op">*</span> <span class="dv">2</span>
<span class="bu">print</span>(repeats)</code></pre></div>
<ol style="list-style-type: decimal">
<li><code>[2, 4, 6, 8, 10, 2, 4, 6, 8, 10]</code></li>
<li><code>[4, 8, 12, 16, 20]</code></li>
<li><code>[[2, 4, 6, 8, 10],[2, 4, 6, 8, 10]]</code></li>
<li><code>[2, 4, 6, 8, 10, 4, 8, 12, 16, 20]</code></li>
</ol>
<p>The technical term for this is <em>operator overloading</em>: a single operator, like <code>+</code> or <code>*</code>, can do different things depending on what it’s applied to.</p>
</div>
</section>
</div>
</div>
</article>
<div class="footer">
<a class="label swc-blue-bg" href="http://software-carpentry.org">Software Carpentry</a>
<a class="label swc-blue-bg" href="https://github.com/swcarpentry/python-novice-inflammation">Source</a>
<a class="label swc-blue-bg" href="mailto:[email protected]">Contact</a>
<a class="label swc-blue-bg" href="LICENSE.html">License</a>
</div>
</div>
<!-- Javascript placed at the end of the document so the pages load faster -->
<script src="http://software-carpentry.org/v5/js/jquery-1.9.1.min.js"></script>
<script src="css/bootstrap/bootstrap-js/bootstrap.js"></script>
<script src='https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-37305346-2', 'auto');
ga('send', 'pageview');
</script>
</body>
</html>