This notebook was put together by Jake Vanderplas for UW's Astro 599 course. Source and license info is on GitHub.
%run talktools.py
(known as "Sequence objects")
list : a mutable ordered array of datatuple : an immutable ordered array of datadict : an unordered mapping from keys to valuesset : an unordered collection of unique elementsThe values in any of these collections can be arbitrary Python objects, and mixing content types is OK.
Note that strings are also sequence objects.
Tuples are denoted with parentheses
t = (12, -1)
print(type(t))
<class 'tuple'>
print(isinstance(t,tuple))
print(len(t))
True 2
Can mix types in a tuple
t = (12, "monty", True, -1.23e6)
print(t[1])
monty
Indexing works the same way as for strings:
print(t[-1])
-1230000.0
t[-2:] # get the last two elements, return as a tuple
(True, -1230000.0)
x = (True) ; print(type(x))
x = (True,) ; print(type(x))
<class 'bool'> <class 'tuple'>
x = ()
type(x), len(x)
(tuple, 0)
x = (,)
File "<ipython-input-9-bd05d59e2976>", line 1 x = (,) ^ SyntaxError: invalid syntax
single-element tuples look like (element,)
tuples cannot be modified. but you can create new one with concatenation
t[2] = False
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-10-9365ccccf007> in <module>() ----> 1 t[2] = False TypeError: 'tuple' object does not support item assignment
t[0:2], False, t[3:]
((12, 'monty'), False, (-1230000.0,))
## the above is
## not what we wanted... need to concatenate
t[0:2] + False + t[3:]
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-12-aaeb0198f3bf> in <module>() 1 ## the above is 2 ## not what we wanted... need to concatenate ----> 3 t[0:2] + False + t[3:] TypeError: can only concatenate tuple (not "bool") to tuple
y = t[0:2] + (False,) + t[3:]
y
(12, 'monty', False, -1230000.0)
t * 2
(12, 'monty', True, -1230000.0, 12, 'monty', True, -1230000.0)
Tuples are most commonly used in functions which return multiple arguments.
Lists are denoted with square brackets
v = [1,2,3]
print(len(v))
print(type(v))
3 <class 'list'>
v[0:2]
[1, 2]
v = ["eggs", "spam", -1, ("monty","python"), [-1.2,-3.5]]
len(v)
5
v[0] ="green egg"
v[1] += ",love it."
v[-1]
[-1.2, -3.5]
v[-1][1] = None
print(v)
['green egg', 'spam,love it.', -1, ('monty', 'python'), [-1.2, None]]
v = v[2:]
print(v)
[-1, ('monty', 'python'), [-1.2, None]]
# let's make a proto-array out of nested lists
vv = [ [1,2], [3,4] ]
len(vv)
2
determinant = vv[0][0] * vv[1][1] - vv[0][1] * vv[1][0]
determinant
-2
the main point here: lists are mutable
v = [1,2,3]
v.append(4)
v.append([-5])
v
[1, 2, 3, 4, [-5]]
Note: lists can be considered objects. Objects are collections of data and associated
methods. In the case of a list, append is a method: it is a function
associated with the object.
v = v[:4]
w = ['elderberries', 'eggs']
v + w
[1, 2, 3, 4, 'elderberries', 'eggs']
v
[1, 2, 3, 4]
v.extend(w)
v
[1, 2, 3, 4, 'elderberries', 'eggs']
v.pop()
'eggs'
v
[1, 2, 3, 4, 'elderberries']
v.pop(0) ## pop the first element
1
v
[2, 3, 4, 'elderberries']
.append(): adds a new element.extend(): concatenates a list/element.pop(): remove an elementv = [1, 3, 2, 3, 4]
v.sort()
v
[1, 2, 3, 3, 4]
reverse is a keyword of the .sort() method
v.sort(reverse=True)
v
[4, 3, 3, 2, 1]
.sort() changes the the list in place
v.index(4) ## lookup the index of the entry 4
0
v.index(3)
1
v.count(3)
2
v.insert(0, "it's full of stars")
v
["it's full of stars", 4, 3, 3, 2, 1]
v.remove(1)
v
["it's full of stars", 4, 3, 3, 2]
IPython is your new best friend: it's tab-completion allows you to explore all methods available to an object. (This only works in IPython)
Type
v.
and then the tab key to see all the available methods:
v.
Once you find a method, type (for example)
v.index?
and press shift-enter: you'll see the documentation of the method
v.index?
This is probably the most important thing you'll learn today
a = ['cat', 'window', 'defenestrate']
for x in a:
print(x, len(x))
cat 3 window 6 defenestrate 12
for i,x in enumerate(a):
print(i, x, len(x))
0 cat 3 1 window 6 2 defenestrate 12
for x in a:
print(x, end=' ')
cat window defenestrate
The syntax for iteration is...
for variable_name in iterable:
# do something with variable_name
range() function¶The range() function creates a list of integers
(actually an iterator, but think of it as a list)
x = range(4)
x
range(0, 4)
total = 0
for val in range(4):
total += val
print("By adding " + str(val) + \
" the total is now " + str(total))
By adding 0 the total is now 0 By adding 1 the total is now 1 By adding 2 the total is now 3 By adding 3 the total is now 6
range([start,] stop[, step])
→ list of integers
total = 0
for val in range(1, 10, 2):
total += val
print("By adding " + str(val) + \
" the total is now " + str(total))
By adding 1 the total is now 1 By adding 3 the total is now 4 By adding 5 the total is now 9 By adding 7 the total is now 16 By adding 9 the total is now 25
Quick Exercise:
Write a loop over the words in this list and print the words longer than three characters in length:
L = ["Oh", "Say", "does", "that", "star",
"spangled", "banner", "yet", "wave"]
{1,2,3,"bingo"}
{1, 2, 3, 'bingo'}
type({1,2,3,"bingo"})
set
type({})
dict
type(set())
set
set("spamIam")
{'I', 'a', 'm', 'p', 's'}
sets have unique elements. They can be compared, differenced, unionized, etc.
a = set("sp")
b = set("am")
print(a, b)
{'p', 's'} {'a', 'm'}
c = set(["a","m"])
c == b
True
"p" in a
True
a | b
{'a', 'm', 'p', 's'}
Dictionaries are one-to-one mappings of objects.
We'll show four ways to make a Dictionary
# number 1... curly braces & colons
d = {"favorite cat": None,
"favorite spam": "all"}
d
{'favorite spam': 'all', 'favorite cat': None}
# number 2
d = dict(one = 1, two=2, cat='dog')
d
{'cat': 'dog', 'two': 2, 'one': 1}
# number 3 ... just start filling in items/keys
d = {} # empty dictionary
d['cat'] = 'dog'
d['one'] = 1
d['two'] = 2
d
{'cat': 'dog', 'two': 2, 'one': 1}
# number 4... start with a list of tuples
mylist = [("cat","dog"), ("one",1), ("two",2)]
dict(mylist)
{'cat': 'dog', 'two': 2, 'one': 1}
dict(mylist) == d
True
Note that there is no guaranteed order in a dictionary!
d = {"favorite cat": None, "favorite spam": "all"}
d[0] # this breaks! Dictionaries have no order
--------------------------------------------------------------------------- KeyError Traceback (most recent call last) <ipython-input-63-d1fc1eca4ebb> in <module>() ----> 1 d[0] # this breaks! Dictionaries have no order KeyError: 0
d["favorite spam"]
'all'
d[0] = "this is a zero"
d
{0: 'this is a zero', 'favorite spam': 'all', 'favorite cat': None}
Dictionaries can contain dictionaries!
d = {'favorites': {'cat': None, 'spam': 'all'},\
'least favorite': {'cat': 'all', 'spam': None}}
d['least favorite']['cat']
'all'
remember: the backslash ('') allows you to across break lines. Not technically needed when defining a dictionary or list
# globals() and locals() store all global and local variables
globals().keys()
dict_keys(['_i62', 'b', 'mylist', 'd', '_i56', 'L', '_i10', '__builtins__', '_i47', '_i11', '_i25', '_i', '_ih', '_ii', '__doc__', '_25', 'v', '_i22', 'x', '_57', '_18', '_i13', '_i29', '_i28', '_50', '_51', 'print_function', '_29', '_28', '_i18', '_i19', '__', '_i14', '_i15', '_i16', '_i17', '_27', '_26', '_i12', '_24', 'vv', '___', '_58', 'i', '_i64', '_8', '_i58', '_i8', '_i9', 'display', 'determinant', '_i2', '_i3', '_i1', '_i6', '_i7', '_i4', '_i5', '_i50', '_i51', '_i52', '_i53', '_i54', '_i55', 't', '_i57', '_i26', '_i59', '_38', '_55', '_i24', '_30', '_31', '_32', '_33', '_13', '_i27', '_36', '_37', '_dh', '_11', '_i21', '_i66', '_16', '_i20', 'get_ipython', 'a', 'c', '_14', '__builtin__', 'HTML', '_34', 'Out', '_i44', '_35', '_i43', '_i42', '_i41', '_i40', '_oh', 'total', '_i45', 'w', 'y', '_i49', '_i48', '_54', '_i38', '_i39', '_i61', '_i32', '_i33', '_i30', '_i31', '_i36', '_i37', '__name__', '__nonzero__', '_i46', '_i65', '_i23', '_i67', '_44', '_52', 'val', '_60', '_', 'quit', '_i60', '_49', '_48', 'In', '_6', '_i34', '_59', '_64', '_iii', '_i63', '_17', '_66', '_65', 'exit', '_sh', '_23', '__warningregistry__', '_i35', '_56', '_22', '_61'])
L = []
for num in range(100):
if (num % 7 == 0) or (num % 11 == 0):
L.append(num)
print(L)
[0, 7, 11, 14, 21, 22, 28, 33, 35, 42, 44, 49, 55, 56, 63, 66, 70, 77, 84, 88, 91, 98, 99]
We can also do this with a list comprehension:
L = [num for num in range(100)\
if (num % 7 == 0) or (num % 11 == 0)]
print(L)
[0, 7, 11, 14, 21, 22, 28, 33, 35, 42, 44, 49, 55, 56, 63, 66, 70, 77, 84, 88, 91, 98, 99]
# Can also operate on each element:
L = [2 * num for num in range(100)\
if (num % 7 == 0) or (num % 11 == 0)]
print(L)
[0, 14, 22, 28, 42, 44, 56, 66, 70, 84, 88, 98, 110, 112, 126, 132, 140, 154, 168, 176, 182, 196, 198]
Example: Below is a list of information on 50 of the largest near-earth asteroids. Given this list of asteroid information, let's find all asteroids with semi-major axis within 0.2AU of earth, and with eccentricities less than 0.5
# Each element is (name, semi-major axis (AU), eccentricity, orbit class)
# source: http://ssd.jpl.nasa.gov/sbdb_query.cgi
Asteroids = [('Eros', 1.457916888347732, 0.2226769029627053, 'AMO'),
('Albert', 2.629584157344544, 0.551788195302116, 'AMO'),
('Alinda', 2.477642943521562, 0.5675993715753302, 'AMO'),
('Ganymed', 2.662242764279804, 0.5339300994578989, 'AMO'),
('Amor', 1.918987277620309, 0.4354863345648127, 'AMO'),
('Icarus', 1.077941311539208, 0.826950446001521, 'APO'),
('Betulia', 2.196489260519891, 0.4876246891992282, 'AMO'),
('Geographos', 1.245477192797457, 0.3355407124897842, 'APO'),
('Ivar', 1.862724540418448, 0.3968541470639658, 'AMO'),
('Toro', 1.367247622946547, 0.4358829575017499, 'APO'),
('Apollo', 1.470694262588244, 0.5598306817483757, 'APO'),
('Antinous', 2.258479598510079, 0.6070051516585434, 'APO'),
('Daedalus', 1.460912865705988, 0.6144629118218898, 'APO'),
('Cerberus', 1.079965807367047, 0.4668134997419173, 'APO'),
('Sisyphus', 1.893726635847921, 0.5383319204425762, 'APO'),
('Quetzalcoatl', 2.544270656955212, 0.5704591861565643, 'AMO'),
('Boreas', 2.271958775354725, 0.4499332278634067, 'AMO'),
('Cuyo', 2.150453953345012, 0.5041719257675564, 'AMO'),
('Anteros', 1.430262719980132, 0.2558054402785934, 'AMO'),
('Tezcatlipoca', 1.709753263222791, 0.3647772103513082, 'AMO'),
('Midas', 1.775954494579457, 0.6503697243919138, 'APO'),
('Baboquivari', 2.646202507670927, 0.5295611095751231, 'AMO'),
('Anza', 2.26415089613359, 0.5371603112900858, 'AMO'),
('Aten', 0.9668828078092987, 0.1827831025175614, 'ATE'),
('Bacchus', 1.078135348117527, 0.3495569270441645, 'APO'),
('Ra-Shalom', 0.8320425524852308, 0.4364726062545577, 'ATE'),
('Adonis', 1.874315684524321, 0.763949321566, 'APO'),
('Tantalus', 1.289997492877751, 0.2990853014998932, 'APO'),
('Aristaeus', 1.599511990737142, 0.5030618532252225, 'APO'),
('Oljato', 2.172056090036035, 0.7125729402616418, 'APO'),
('Pele', 2.291471988746353, 0.5115484924883255, 'AMO'),
('Hephaistos', 2.159619960333728, 0.8374146846143349, 'APO'),
('Orthos', 2.404988778495748, 0.6569133796135244, 'APO'),
('Hathor', 0.8442121506103012, 0.4498204013480316, 'ATE'),
('Beltrovata', 2.104690977122337, 0.413731105995413, 'AMO'),
('Seneca', 2.516402574514213, 0.5708728441169761, 'AMO'),
('Krok', 2.152545170235639, 0.4478259793515817, 'AMO'),
('Eger', 1.404478323548423, 0.3542971360331806, 'APO'),
('Florence', 1.768227407864309, 0.4227761019048867, 'AMO'),
('Nefertiti', 1.574493139339916, 0.283902719273878, 'AMO'),
('Phaethon', 1.271195939723604, 0.8898716672181355, 'APO'),
('Ul', 2.102493486378346, 0.3951143067760007, 'AMO'),
('Seleucus', 2.033331705805067, 0.4559159977082651, 'AMO'),
('McAuliffe', 1.878722427225527, 0.3691521497610656, 'AMO'),
('Syrinx', 2.469752836845105, 0.7441934504192601, 'APO'),
('Orpheus', 1.209727780883745, 0.3229034563257626, 'APO'),
('Khufu', 0.989473784873371, 0.468479627898914, 'ATE'),
('Verenia', 2.093231870619781, 0.4865133359612604, 'AMO'),
('"Don Quixote"', 4.221712367193639, 0.7130894892477316, 'AMO'),
('Mera', 1.644476057737928, 0.3201425983025733, 'AMO')]
orbit_class = {'AMO':'Amor', 'APO':'Apollo', 'ATE':'Aten'}
# first we'll build the list using loops.
L = []
for data in Asteroids:
name, a, e, t = data
if abs(a - 1) < 0.2 and e < 0.5:
L.append(name)
print(L)
['Cerberus', 'Aten', 'Bacchus', 'Ra-Shalom', 'Hathor', 'Khufu']
# now with a list comprehension...
L = [name for (name, a, e, t) in Asteroids
if abs(a - 1) < 0.2 and e < 0.5]
print(L)
['Cerberus', 'Aten', 'Bacchus', 'Ra-Shalom', 'Hathor', 'Khufu']
Here is how we could create a dictionary from the list
D = dict([(name, (a, e, t)) for (name, a, e, t) in Asteroids])
print(D['Eros'])
print(D['Amor'])
(1.457916888347732, 0.2226769029627053, 'AMO') (1.918987277620309, 0.4354863345648127, 'AMO')
Using the above Asteroid list,
The output should be formatted like this:
Asteroid name a (AU) e class
-----------------------------------------
Eros 1.4578 0.2226 Amor
Albert 2.6292 0.5518 Amor
.
.
.
Bonus points if you can get the columns to line up nicely!