5. Comprehensions

5.1. Simple usage

5.1.1. Traditional

numbers = []

for x in range(0, 5):
    numbers.append(x+10)

# numbers = [10, 11, 12, 13, 14]

5.1.2. List Comprehension

numbers = [x+10 for x in range(0, 5)]
# [10, 11, 12, 13, 14]

5.1.3. Set Comprahension

numbers = {x+10 for x in range(0, 5)}
# {10, 11, 12, 13, 14}

5.1.4. Dict Comprahension

{x: x+10 for x in range(0, 5)}
# {0:10, 1:11, 2:12, 3:13, 4:14}
{x+10: x for x in range(0, 5)}
# {10:0, 11:1, 12:2, 13:3, 14:4}
{x+10: x+10 for x in range(0, 5)}
# {10:10, 11:11, 12:12, 13:13, 14:14}

5.1.5. Tuple comprahension?!

(x+10 for x in range(0, 5))
# <generator object <genexpr> at 0x11eaef570>

5.2. Conditional Comprehension

5.2.1. Traditional

even_numbers = []

for x in range(0, 10):
    if x % 2 == 0:
        even_numbers.append(x)

print(even_numbers)
# [0, 2, 4, 6, 8]

5.2.2. Comprehensions

even_numbers = [x for x in range(0, 10) if x % 2 == 0]

print(even_numbers)
# [0, 2, 4, 6, 8]

5.3. Why?

5.3.1. Filtering results

DATA = [
    ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
    (5.8, 2.7, 5.1, 1.9, 'virginica'),
    (5.1, 3.5, 1.4, 0.2, 'setosa'),
    (5.7, 2.8, 4.1, 1.3, 'versicolor'),
    (6.3, 2.9, 5.6, 1.8, 'virginica'),
    (6.4, 3.2, 4.5, 1.5, 'versicolor'),
    (4.7, 3.2, 1.3, 0.2, 'setosa'),
    (7.0, 3.2, 4.7, 1.4, 'versicolor'),
]

setosa = [x for x in DATA if x[4] == 'setosa']
print(setosa)
# [
#   (5.1, 3.5, 1.4, 0.2, 'setosa'),
#   (4.7, 3.2, 1.3, 0.2, 'setosa')
# ]

5.3.2. Filtering with complex expressions

DATA = [
    ('Sepal length', 'Sepal width', 'Petal length', 'Petal width', 'Species'),
    (5.8, 2.7, 5.1, 1.9, 'virginica'),
    (5.1, 3.5, 1.4, 0.2, 'setosa'),
    (5.7, 2.8, 4.1, 1.3, 'versicolor'),
    (6.3, 2.9, 5.6, 1.8, 'virginica'),
    (6.4, 3.2, 4.5, 1.5, 'versicolor'),
    (4.7, 3.2, 1.3, 0.2, 'setosa'),
    (7.0, 3.2, 4.7, 1.4, 'versicolor'),
]


def is_setosa(record):
    if record[-1] == 'setosa':
        return True
    else:
        return False


output = [x for x in DATA if is_setosa(x)]

print(output)
# [
#   (5.1, 3.5, 1.4, 0.2, 'setosa'),
#   (4.7, 3.2, 1.3, 0.2, 'setosa')
# ]

5.3.3. Applying function to each output element

[float(x) for x in range(0, 10)]
[float(x) for x in range(0, 10) if x % 2 == 0]

5.3.4. Returning nested objects

def get_tuple(number):
    return number, number+10

output = [get_tuple(x) for x in range(0, 5)]

print(output)
# [
#   (0, 10),
#   (1, 11),
#   (2, 12),
#   (3, 13),
#   (4, 14)
# ]
def get_dict(number):
    if number % 2 == 0:
        return {'number': number, 'status': 'even'}
    else:
        return {'number': number, 'status': 'odd'}

output = [get_dict(x) for x in range(0, 5)]

print(output)
# [
#    {'number': 0, 'status': 'even'},
#    {'number': 1, 'status': 'odd'},
#    {'number': 2, 'status': 'even'},
#    {'number': 3, 'status': 'odd'},
#    {'number': 4, 'status': 'even'},
# ]

5.3.5. Reversing dict keys with values

my_dict = {'x': 1, 'y': 2}

my_dict.items()
# [
#    ('x', 1),
#    ('y', 2),
# ]
my_dict = {'x': 1, 'y': 2}

{value: key for key, value in my_dict.items()}
# {1:'x', 2:'y'}
my_dict = {'x': 1, 'y': 2}

{v:k for k,v in my_dict.items()}
# {1:'x', 2:'y'}

5.3.6. Quick parsing lines

line = 'jose:x:1000:1000:José Jiménez:/home/jose:/bin/bash'
paths = []

for record in line.split(':'):
    if record.startswith('/'):
        paths.append(record)

print(paths)
# ['/home/jose', '/bin/bash']
line = 'jose:x:1000:1000:José Jiménez:/home/jose:/bin/bash'
paths = [x for x in line.split(':') if x.startswith('/')]

print(paths)
# ['/home/jose', '/bin/bash']

5.4. Advanced usage for Comprehensions and Generators

Note

More in chapter Generators and Comprehensions

5.5. Assignments

5.5.1. Report card

  1. Przekonwertuj skalę ocen (2, 3, 3.5, 4, 4.5, 5) na listę float za pomocą inline for
  2. Użytkownik podaje oceny jako int lub float
  3. Jeżeli ocena jest na liście dopuszczalnych ocen, dodaje ją do dzienniczka
  4. Jeżeli wciśnięto sam Enter, oznacza to koniec wpisywania do dzienniczka
  5. Jeżeli wpisano cyfrę nie znajdującą się na liście dopuszczalnych ocen, wyświetl informację “Grade is not allowed” i dalej kontynuuj wpisywanie
  6. Na zakończenie wyświetl wyliczoną dla dzienniczka średnią arytmetyczną z ocen
About:
  • Filename: loop_report_card.py
  • Lines of code to write: 15 lines
  • Estimated time of completion: 10 min
The whys and wherefores:
 
  • Wczytywanie ciągu znaków od użytkownika
  • Generowanie struktur danych i konwersja typów
  • Weryfikacja ciągu wprowadzonego od użytkownika
  • Korzystanie z pętli oraz instrukcji wychodzących
  • Konwersja typów i rzutowanie
  • Sprawdzanie czy obiekt jest instancją klasy
  • Wykorzystanie funkcji wbudowanych
Hints:
  • average = sum(...) / len(...)