updated from Atlas

This commit is contained in:
Luciano Ramalho
2015-04-01 22:48:56 -03:00
parent aab93699a4
commit 573e1a94c4
109 changed files with 5 additions and 6 deletions

View File

@@ -0,0 +1,20 @@
import random
import collections
SIZE = 15
random.seed(1729)
target_list = [random.randrange(SIZE*2) for i in range(SIZE)]
target_list.sort()
random.seed(1729)
display_list = [' '] * SIZE
occurrences = collections.Counter()
for i in range(SIZE):
new_item = random.randrange(SIZE*2)
pos = target_list.index(new_item) + occurrences[new_item]
occurrences[new_item] += 1
display_list[pos] = '%2s, ' % new_item
print('[' + ''.join(display_list) + ']')

View File

@@ -0,0 +1,29 @@
"""
>>> bisect_find([], 1)
-1
>>> import array
>>> import random
>>> SIZE = 10
>>> my_array = array.array('l', range(0, SIZE, 2))
>>> random.seed(42)
>>> for i in range(SIZE):
... print(i, bisect_find(my_array, i))
0 0
1 -1
2 1
3 -1
4 2
5 -1
6 3
7 -1
8 4
9 -1
"""
from bisect import bisect
def bisect_find(seq, item):
left_pos = bisect(seq, item) - 1
return left_pos if seq and seq[left_pos] == item else -1

View File

@@ -0,0 +1,29 @@
"""
>>> bisect_in([], 1)
False
>>> import array
>>> import random
>>> SIZE = 10
>>> my_array = array.array('l', range(0, SIZE, 2))
>>> random.seed(42)
>>> for i in range(SIZE):
... print(i, bisect_in(my_array, i))
0 True
1 False
2 True
3 False
4 True
5 False
6 True
7 False
8 True
9 False
"""
from bisect import bisect
def bisect_in(seq, item):
pos = bisect(seq, item)
return seq[pos-1] == item if seq else False

View File

@@ -0,0 +1,32 @@
"""
bisect_time.py
"""
import timeit
SETUP = '''
SIZE = 10**6
import array
import random
from bisect_find import bisect_find
random.seed(42)
haystack = [random.randrange(SIZE)*2 for i in range(SIZE)]
needles = [random.choice(haystack) + i % 2 for i in range(20)]
'''
BISECT = '''
print('bisect:', end=' ')
for n in needles:
print(bisect_find(haystack, n), end=' ')
print()
'''
SORT = '''
print(' in:', end=' ')
for n in needles:
print(int(n in haystack), end=' ')
print()
'''
print(min(timeit.Timer(BISECT, SETUP).repeat(7, 1)))
print(min(timeit.Timer(SORT, SETUP).repeat(7, 1)))

Binary file not shown.

View File

@@ -0,0 +1,10 @@
1 0 LOAD_NAME 0 (s)
3 LOAD_NAME 1 (a)
6 DUP_TOP_TWO
7 BINARY_SUBSCR <1>
8 LOAD_NAME 2 (b)
11 INPLACE_ADD <2>
12 ROT_THREE
13 STORE_SUBSCR <3>
14 LOAD_CONST 0 (None)
17 RETURN_VALUE

View File

@@ -0,0 +1,54 @@
>>> from frenchdeck2 import FrenchDeck2, Card
>>> beer_card = Card('7', 'diamonds')
>>> beer_card
Card(rank='7', suit='diamonds')
>>> deck = FrenchDeck2()
>>> len(deck)
52
>>> deck[:3]
[Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
>>> deck[12::13]
[Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
>>> Card('Q', 'hearts') in deck
True
>>> Card('Z', 'clubs') in deck
False
>>> for card in deck: # doctest: +ELLIPSIS
... print(card)
Card(rank='2', suit='spades')
Card(rank='3', suit='spades')
Card(rank='4', suit='spades')
...
>>> for card in reversed(deck): # doctest: +ELLIPSIS
... print(card)
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
...
>>> for n, card in enumerate(deck, 1): # doctest: +ELLIPSIS
... print(n, card)
1 Card(rank='2', suit='spades')
2 Card(rank='3', suit='spades')
3 Card(rank='4', suit='spades')
...
>>> def alt_color_rank(card):
... rank_value = FrenchDeck2.ranks.index(card.rank)
... suits = 'diamonds clubs hearts spades'.split()
... return rank_value * len(suits) + suits.index(card.suit)
Rank test:
>>> alt_color_rank(Card('2', 'diamonds'))
0
>>> alt_color_rank(Card('A', 'spades'))
51
>>> for card in sorted(deck, key=alt_color_rank): # doctest: +ELLIPSIS
... print(card)
Card(rank='2', suit='diamonds')
Card(rank='2', suit='clubs')
Card(rank='2', suit='hearts')
...
Card(rank='A', suit='clubs')
Card(rank='A', suit='hearts')
Card(rank='A', suit='spades')

View File

@@ -0,0 +1,26 @@
import collections
Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck2(collections.MutableSequence):
ranks = [str(n) for n in range(2, 11)] + list('JQKA')
suits = 'spades diamonds clubs hearts'.split()
def __init__(self):
self._cards = [Card(rank, suit) for suit in self.suits
for rank in self.ranks]
def __len__(self):
return len(self._cards)
def __getitem__(self, position):
return self._cards[position]
def __setitem__(self, position, value): # <1>
self._cards[position] = value
def __delitem__(self, position): # <2>
del self._cards[position]
def insert(self, position, value): # <3>
self._cards.insert(position, value)

View File

@@ -0,0 +1,49 @@
FILENAME = 'metro_areas.txt'
class MetroArea:
def __init__(self, name, country, pop, pop_change, area):
self.name = name
self.country = country
self.pop = pop
self.pop_change = pop_change
self.area = area
def __repr__(self):
return '{0.name}, {0.country} ({0.pop})'.format(self)
def density(self):
return self.pop / self.area
def load():
metro_areas = []
with open(FILENAME, encoding='utf-8') as text:
for line in text:
if line.startswith('#'):
continue
# Country Name Rank Population Yr_change % Area(km2) Pop/km2
country, name, _, pop, pop_change, _, area, _ = line.split('\t')
pop = float(pop.replace(',', ''))
pop_change = float(pop_change)
area = float(area)
metro_areas.append((name, country, pop, pop_change, area))
return metro_areas
def list(metro_areas):
print('{:^18} {:>6} {:>4} {:>6}'.format('name', 'cc', 'pop', 'chg', 'area'))
for metro in metro_areas:
print('{:18} {:2} {:6.0f} {:4.0f} {:6.0f}'.format(*metro))
def list_instances(metro_areas):
metro_areas = [MetroArea(*fields) for fields in metro_areas]
for metro in metro_areas:
print(metro)
if __name__ == '__main__':
#list(load())
list_instances(load())

View File

@@ -0,0 +1,29 @@
# THE 20 LARGEST WORLD METROPOLITAN AREAS, 2003: DATA FOR FORSTALL DEFINITIONS
# (Populations in thousands estimated for 1 July 2003.)
# CC Name Rank Population Yr_change % Area(km2) Pop/km2
JP Tokyo 1 32,450 213 0.66 8014 4049.2
KR Seoul 2 20,550 227 1.12 5076 4048.5
MX Mexico City 3 20,450 307 1.54 7346 2783.8
US New York 4 19,750 120 0.61 17884 1104.3
IN Mumbai (Bombay) 5 19,200 472 2.53 2350 8170.2
ID Jakarta 6 18,900 225 1.21 5100 3705.9
BR Sao Paulo 7 18,850 289 1.57 8479 2223.1
IN Delhi-New Delhi 8 18,600 686 3.86 3182 5845.4
JP Osaka-Kobe-Kyoto 9 17,375 28 0.16 6930 2507.2
CN Shanghai 10 16,650 335 2.07 5177 3216.1
PH Manila 11 16,300 461 2.96 2521 6465.7
CN Hong Kong-Shenzhen 12 15,800 797 5.42 3051 5178.6
US Los Angeles 13 15,250 205 1.38 10780 1414.7
IN Kolkata (Calcutta) 14 15,100 257 1.74 1785 8459.4
RU Moscow 15 15,000 103 0.69 14925 1005.0
EG Cairo 16 14,450 257 1.89 1600 9031.3
AR Buenos Aires 17 13,170 79 0.62 10888 1209.6
UK London 18 12,875 112 0.87 11391 1130.3
CN Beijing 19 12,500 301 2.49 6562 1904.9
PK Karachi 20 11,800 370 3.43 1100 10727.3
# Data source:
# WHICH ARE THE LARGEST? WHY PUBLISHED POPULATIONS
# FOR MAJOR WORLD URBAN AREAS VARY SO GREATLY
# Richard L. Forstall, Richard P. Greene, James B. Pick
# http://web.archive.org/web/20130114203922/http://www.uic.edu/cuppa/cityfutures/papers/webpapers/cityfuturespapers/session3_4/3_4whicharethe.pdf
# Country codes added by L. Ramalho

View File

@@ -0,0 +1,21 @@
invoice = """
0.....6.................................40........52...55........
1909 Pimoroni PiBrella $17.50 3 $52.50
1489 6mm Tactile Switch x20 $4.95 2 $9.90
1510 Panavise Jr. - PV-201 $28.00 1 $28.00
1601 PiTFT Mini Kit 320x240 $34.95 1 $34.95
"""
structure = dict(
SKU = slice(0, 6),
DESCRIPTION = slice(6, 40),
UNIT_PRICE = slice(40, 52),
QUANTITY = slice(52, 55),
ITEM_TOTAL = slice(55, None),
)
for line in invoice.split('\n')[2:]:
line_item = {}
for field, chunk in structure.items():
line_item[field] = line[chunk].strip()
print(line_item)

View File

@@ -0,0 +1,75 @@
>>> from sentence import Sentence
>>> s = Sentence('The time has come')
>>> s
Sentence('The time has come')
>>> s[0]
'The'
>>> list(s)
['The', 'time', 'has', 'come']
>>> s = Sentence('"The time has come," the Walrus said,')
>>> s
Sentence('"The time ha... Walrus said,')
>>> s[0]
'The'
>>> s[1]
'time'
>>> for word in s:
... print(word)
The
time
has
come
the
Walrus
said
>>> list(s)
['The', 'time', 'has', 'come', 'the', 'Walrus', 'said']
>>> s[-2]
'Walrus'
>>> s[2:4]
['has', 'come']
>>> s[:4]
['The', 'time', 'has', 'come']
>>> s[4:]
['the', 'Walrus', 'said']
>>> s3 = Sentence('Pig and Pepper')
>>> it = iter(s3)
>>> it # doctest: +ELLIPSIS
<iterator object at 0x...>
>>> next(it)
'Pig'
>>> next(it)
'and'
>>> next(it)
'Pepper'
>>> next(it)
Traceback (most recent call last):
...
StopIteration
>>> list(it)
[]
>>> list(iter(s3))
['Pig', 'and', 'Pepper']
>>> s = Sentence('''The right of the people to be secure in
... their persons, houses, papers, and effects, against
... unreasonable searches and seizures, shall not be violated,''')
>>> s
Sentence('The right of... be violated,')
>>> list(s) # doctest: +ELLIPSIS
['The', 'right', 'of', 'the', 'people', ... 'not', 'be', 'violated']
>>> s = Sentence('Agora vou-me. Ou me vão?')
>>> s
Sentence('Agora vou-me. Ou me vão?')
>>> list(s)
['Agora', 'vou', 'me', 'Ou', 'me', 'vão']

View File

@@ -0,0 +1,24 @@
"""
Sentence: access words by index
"""
import re
import reprlib
RE_WORD = re.compile('\w+')
class Sentence:
def __init__(self, text):
self.text = text
self.words = RE_WORD.findall(text) # <1>
def __getitem__(self, index):
return self.words[index] # <2>
def __len__(self, index): # <3>
return len(self.words)
def __repr__(self):
return 'Sentence(%s)' % reprlib.repr(self.text) # <4>

View File

@@ -0,0 +1,79 @@
>>> from sentence_slice import SentenceSlice
>>> s = SentenceSlice('the')
>>> s.tokens
['the']
>>> s.words
['the']
>>> s = SentenceSlice('the quick brown fox')
>>> s.tokens
['the', ' ', 'quick', ' ', 'brown', ' ', 'fox']
>>> s.words
['the', 'quick', 'brown', 'fox']
>>> s[0]
'the'
>>> s[1]
'quick'
>>> s[-1]
'fox'
>>> s[2:4]
SentenceSlice('brown fox')
>>> s[1:]
SentenceSlice('quick brown fox')
>>> s[:3]
SentenceSlice('the quick brown')
>>> s = SentenceSlice('"The time has come," the Walrus said,')
>>> s.tokens
['"', 'The', ' ', 'time', ' ', 'has', ' ', 'come', ',"', ' ', 'the', ' ', 'Walrus', ' ', 'said', ',']
>>> s.words
['The', 'time', 'has', 'come', 'the', 'Walrus', 'said']
>>> s[:3]
SentenceSlice('"The time has')
>>> s[:4]
SentenceSlice('"The time has come,"')
>>> s[4:]
SentenceSlice('the Walrus said,')
>>> s[1:5]
SentenceSlice('time has come," the')
>>> s[1:6]
SentenceSlice('time has come," the Walrus')
>>> s[1:7]
SentenceSlice('time has com... Walrus said,')
>>> s[1:8]
SentenceSlice('time has com... Walrus said,')
>>> s[6:]
SentenceSlice('said,')
>>> s[7:]
SentenceSlice('')
>>> s[8:]
SentenceSlice('')
>>> s[:-3]
SentenceSlice('"The time has come,"')
>>> s[-4:-2]
SentenceSlice('come," the')
>>> s[0:2]
SentenceSlice('"The time')
>>> s = SentenceSlice('''"The time has come," the Walrus said,
... "To talk of many things:"''')
>>> s.tokens
['"', 'The', ' ', 'time', ' ', 'has', ' ', 'come', ',"', ' ', 'the', ' ', 'Walrus', ' ', 'said', ',', '\n', '"', 'To', ' ', 'talk', ' ', 'of', ' ', 'many', ' ', 'things', ':"']
>>> s.words
['The', 'time', 'has', 'come', 'the', 'Walrus', 'said', 'To', 'talk', 'of', 'many', 'things']
>>> s = SentenceSlice('Agora vou-me. Ou me vão?')
>>> s.tokens
['Agora', ' ', 'vou', '-', 'me', '.', ' ', 'Ou', ' ', 'me', ' ', 'vão', '?']
>>> s.words
['Agora', 'vou', 'me', 'Ou', 'me', 'vão']
>>> s[1:]
SentenceSlice('vou-me. Ou me vão?')
>>> s[:2]
SentenceSlice('Agora vou-')
>>> s[2:]
SentenceSlice('-me. Ou me vão?')

View File

@@ -0,0 +1,66 @@
"""
SentenceSlice: access words by index, sub-sentences by slices
"""
import re
import reprlib
RE_TOKEN = re.compile('\w+|\s+|[^\w\s]+')
RE_WORD = re.compile('\w+')
RE_PUNCTUATION = re.compile('[^\w\s]+')
class SentenceSlice:
def __init__(self, text):
self.text = text
self.tokens = RE_TOKEN.findall(text)
self.words = [t for t in self.tokens if RE_WORD.match(t)]
self.word_index = [i for i, t in enumerate(self.tokens)
if RE_WORD.match(t)]
def __repr__(self):
return 'SentenceSlice(%s)' % reprlib.repr(self.text)
def __getitem__(self, position):
if isinstance(position, slice):
if position.step is not None:
raise LookupError('slice step is not supported')
start, stop = self._handle_defaults(position)
start, stop = self._widen(start, stop)
tokens = self.tokens[start:stop]
return SentenceSlice(''.join(tokens))
else:
return self.words[position]
def __len__(self, index):
return len(self.words)
# helper functions -- implementation detail
def _handle_defaults(self, position):
"""handle missing or overflow/underflow start/stop"""
if position.start is None: # missing
start = 0
elif position.start >= len(self.word_index): # overflow
start = len(self.tokens)
else:
start = self.word_index[position.start]
if (position.stop is None # missing
or position.stop > len(self.word_index)): # overflow
stop = self.word_index[-1]
else:
stop = self.word_index[position.stop-1]
return start, stop + 1 # stop after last word selected
def _widen(self, start, stop):
"""widen range of tokens to get punctuation to the left of
start and to the right of stop"""
if start < len(self.tokens):
while (start > 0 and
RE_PUNCTUATION.match(self.tokens[start-1])):
start -= 1
while (stop < len(self.tokens) and
RE_PUNCTUATION.match(self.tokens[stop])):
stop += 1
return start, stop

View File

@@ -0,0 +1,33 @@
"""
>>> sd = SliceDump()
>>> sd[1]
1
>>> sd[2:5]
slice(2, 5, None)
>>> sd[:2]
slice(None, 2, None)
>>> sd[7:]
slice(7, None, None)
>>> sd[:]
slice(None, None, None)
>>> sd[1:9:3]
slice(1, 9, 3)
>>> sd[1:9:3, 2:3]
(slice(1, 9, 3), slice(2, 3, None))
>>> s = sd[1:9:3]
>>> s.indices(20)
(1, 9, 3)
>>> s.indices(5)
(1, 5, 3)
>>> s.indices(1)
(1, 1, 3)
>>> s.indices(0)
(0, 0, 3)
"""
class SliceDump:
def __getitem__(self, pos):
return pos

View File

@@ -0,0 +1,38 @@
"""
>>> s = SliceDemo()
>>> s[1]
__getitem__: 1
1
>>> s[2:5]
__getitem__: slice(2, 5, None)
[2, 3, 4]
>>> s[:2]
__getitem__: slice(None, 2, None)
[0, 1]
>>> s[7:]
__getitem__: slice(7, None, None)
[7, 8, 9]
>>> s[:]
__getitem__: slice(None, None, None)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> s[1:9:3]
__getitem__: slice(1, 9, 3)
[1, 4, 7]
>>> s[1:9:3, 2:3]
__getitem__: (slice(1, 9, 3), slice(2, 3, None))
ERROR: list indices must be integers, not tuple
"""
class SliceDemo:
def __init__(self):
self.items = list(range(10))
def __getitem__(self, pos):
print('__getitem__:', pos)
try:
return self.items.__getitem__(pos)
except TypeError as e:
print('ERROR:', e)

View File

@@ -0,0 +1,38 @@
"""
Extended slicing:
>>> s = SliceViewer()
>>> s[1]
1
>>> s[:]
slice(None, None, None)
>>> s[1:2]
slice(1, 2, None)
>>> s[1:2:3]
slice(1, 2, 3)
>>> s[1:2:3:4]
Traceback (most recent call last):
...
SyntaxError: invalid syntax
N-dimensional indexing:
>>> s[1, 2]
(1, 2)
N-dimensional slicing:
>>> s[1:3, 2]
(slice(1, 3, None), 2)
>>> s[1, :2:]
(1, slice(None, 2, None))
>>> s[:, :]
(slice(None, None, None), slice(None, None, None))
"""
class SliceViewer:
def __getitem__(self, position):
return position

View File

@@ -0,0 +1,43 @@
"""string concatenation demos"""
from time import perf_counter
def load_lines():
with open('war-and-peace.txt') as fp:
return fp.readlines() * 100 # replace with 200 or more for surprises!!!
def chrono(f):
def inner(lines):
t0 = perf_counter()
text = f(lines)
elapsed = perf_counter() - t0
print('%15s: %fs' % (f.__name__, elapsed))
return text
return inner
@chrono
def iadd_joiner(lines):
text = ''
for line in lines:
text += line
return text
@chrono
def list_joiner(lines):
parts = []
for line in lines:
parts.append(line)
return ''.join(parts)
@chrono
def genexp_joiner(lines):
return ''.join(line for line in lines)
if __name__=='__main__':
lines = load_lines()
print('joining %s lines' % len(lines))
text0 = iadd_joiner(lines)
text1 = list_joiner(lines)
text2 = genexp_joiner(lines)
assert len(text0) == len(text1) == len(text2), repr(
(len(text0), len(text1), len(text2)))

173
attic/sequences/table.py Normal file
View File

@@ -0,0 +1,173 @@
"""
=============
Row tests
=============
>>> row = Row([1, 2, 3, 4])
>>> row[1]
2
>>> row[1:3]
Row([2, 3])
=============
Table tests
=============
Create an empty table
>>> t3x4 = Table.blank(3, 4)
>>> t3x4
Table(Row([None, None, None, None]),
Row([None, None, None, None]),
Row([None, None, None, None]))
>>> for i in range(3):
... for j in range(4):
... t3x4[i][j] = chr(65 + i * 4 + j)
...
>>> t3x4
Table(Row(['A', 'B', 'C', 'D']),
Row(['E', 'F', 'G', 'H']),
Row(['I', 'J', 'K', 'L']))
>>> t3x4[1]
Row(['E', 'F', 'G', 'H'])
>>> t3x4[1:]
Table(Row(['E', 'F', 'G', 'H']),
Row(['I', 'J', 'K', 'L']))
>>> t3x4[1][2]
'G'
>>> t3x4[1, 2]
'G'
Slicing returns a table, so index 2 below would be trying to get row index 2
of a table that has only rows 0 and 1:
>>> t3x4[1:][2]
Traceback (most recent call last):
...
IndexError: no row at index 2 of 2-row table
>>> t3x4[:, 2]
Table(Row(['C']),
Row(['G']),
Row(['K']))
>>> t3x4[1:, 2]
Table(Row(['G']),
Row(['K']))
>>> t3x4[1, 2:]
Row(['G', 'H'])
>>> t3x4[:, 1:3]
Table(Row(['B', 'C']),
Row(['F', 'G']),
Row(['J', 'K']))
>>> t3x4[:, :]
Table(Row(['A', 'B', 'C', 'D']),
Row(['E', 'F', 'G', 'H']),
Row(['I', 'J', 'K', 'L']))
>>> t3x4[:, :] == t3x4
True
===============
Error handling
===============
>>> t3x4[5]
Traceback (most recent call last):
...
IndexError: no row at index 5 of 3-row table
>>> t3x4[1,]
Traceback (most recent call last):
...
IndexError: index must be [i] or [i, j]
>>> t3x4[1, 2, 3]
Traceback (most recent call last):
...
IndexError: index must be [i] or [i, j]
>>> t3x4[10:, 2]
Traceback (most recent call last):
...
ValueError: Table must have at least one row.
>>> t3x4[1, 20:]
Traceback (most recent call last):
...
ValueError: Row must have at least one cell.
"""
import collections
class Row(collections.UserList):
def __init__(self, cells):
super().__init__(cells)
if len(self) < 1:
raise ValueError('Row must have at least one cell.')
def __getitem__(self, position):
if isinstance(position, slice):
return Row(self.data[position]) # build sub-row
else:
return self.data[position] # return cell value
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.data)
class Table(collections.UserList):
"""A table with rows, all of the same width"""
def __init__(self, rows):
super().__init__(Row(r) for r in rows)
if len(self) < 1:
raise ValueError('Table must have at least one row.')
self.width = self.check_width()
def check_width(self):
row_widths = {len(row) for row in self.data}
if len(row_widths) > 1:
raise ValueError('All rows must have equal length.')
return row_widths.pop()
@classmethod
def blank(class_, rows, columns, filler=None):
return class_([[filler] * columns for i in range(rows)])
def __repr__(self):
prefix = '%s(' % self.__class__.__name__
indent = ' ' * len(prefix)
rows = (',\n' + indent).join(
repr(row) for row in self.data)
return prefix + rows + ')'
def _get_indexes(self, position):
if isinstance(position, tuple): # multiple indexes
if len(position) == 2: # two indexes: t[i, j]
return position
else:
raise IndexError('index must be [i] or [i, j]')
else: # one index: t[i]
return position, None
def __getitem__(self, position):
i, j = self._get_indexes(position)
if isinstance(i, slice):
if j is None: # build sub-table w/ full rows
return Table(self.data[position])
else: # build sub-table w/ sub-rows
return Table(cells[j] for cells in self.data[i])
else: # i is number
try:
row = self.data[i]
except IndexError:
msg = 'no row at index %r of %d-row table'
raise IndexError(msg % (position, len(self)))
if j is None: # return row at table[i]
return row
else:
return row[j] # return row[j] or row[a:b]

View File

@@ -0,0 +1,14 @@
>>> coordinates = (-23.547778, -46.635833)
>>> lat, long_ = coordinates
>>> long_
-46.635833
>>> lat
-23.547778
>>> traveler_ids = [('USA', '311975855'), ('BRA', 'CE342567'), ('ESP', 'XDA205856')]
>>> for country, passport_no in sorted(traveler_ids):
... print('%s:%s' % (country, passport_no))
BRA:CE342567
ESP:XDA205856
USA:311975855

File diff suppressed because it is too large Load Diff