#!/usr/bin/python3 # -*- coding: utf-8 -*- """ List, Set, and Dict comprehensions. """ # %% List comprehensions """ Comprehensions are an elegant way to create lists, sets, or dicts Instead of this: new_list = [] for member in iterable: new_list.append("expression optionally involving member") General form: new_list = ["expression optionally involving member" for member in iterable] where: expression can be 1) the member itself, 2) a call to a method using the member, or 3) any other valid expression that returns a value. member is the object or value in the list or iterable. iterable is a list, set, sequence, generator, or any other object that can return its elements one at a time (an iterable) Comprehensions may also have a condition new_list = [] for member in iterable: if condition: new_list.append("expression optionally involving member") is the same as: new_list = ["expression optionally involving member" for member in iterable if condition] Where the conditional can test any valid expression. Comprehension conditionals allow list comprehensions to filter values. """ # Longest, easiest squares = [] for x in range(10): squares.append(x ** 2) print(squares) # Obscure use of map and lambda function (preview of more to come later) squares = list(map(lambda x: x ** 2, range(10))) print(squares) # Short and easy once you know how to read them! squares = [x ** 2 for x in range(10)] print(squares) # Another loop example: shark_letters = [] for letter in "shark": shark_letters.append(letter.upper()) print(shark_letters) # and the comprehension analogue shark_letters = [letter.upper() for letter in "shark"] print(shark_letters) # Example looping through one list to create another celsius = [39.2, 36.5, 37.3, 37.8] fahrenheit = [((float(9) / 5) * x + 32) for x in celsius] print(fahrenheit) """ Reminder: A list comprehension can be extended with an optional conditional clause that filters out elements from the resulting list. new_list = [expression for member in iterable if condition] """ fish_tuple = ("blowfish", "clownfish", "catfish", "octopus") fish_list = [fish for fish in fish_tuple if fish != "octopus"] print(fish_list) # To create a list of integers which specify the length of each word in a # certain sentence, but only if the word is not the word "the". sentence = "the quick brown fox jumps over the lazy dog" words = sentence.split() word_lengths = [] for word in words: if word != "the": word_lengths.append(len(word)) print(words) print(word_lengths) # and the comprehension sentence = "the quick brown fox jumps over the lazy dog" words = sentence.split() word_lengths = [len(word) for word in words if word != "the"] print(words) print(word_lengths) # Another example: # Get a list of integers from the user numbers = [int(i) for i in input("Enter numbers:").split()] print(numbers) # Filter out odd numbers even_numbers = [i for i in numbers if (i % 2) == 0] print("Even numbers only:", even_numbers) # If you need a more complex filter than a simple condition, # then you can even move the conditional logic to a separate function sentence = "Ted came back from Mars because he missed his friends." def is_consonant(letter: str) -> bool: vowels = "aeiou" return letter.isalpha() and letter.lower() not in vowels consonants = [i for i in sentence if is_consonant(i)] print(consonants) """ You can place the conditional at the end of the statement for simple filtering, but what if you want to change a member value instead of filtering it out? If so, place the conditional near the beginning of the expression: new_list = [expression with ternary if/else for member in iterable] Note: this is not actually a special case of the comprehension, but just the use of a simple ternary as the expression. Recall ternary exrpession: a if condition else b First condition is evaluated, then exactly one of either a or b is evaluated and returned based on the Boolean value of condition. If condition evaluates to True, then a is evaluated and returned but b is ignored, or else when b is evaluated and returned but a is ignored. That as a whole unit, can be the first epression of the list comprehension. """ original_prices = [1.25, -9.45, 10.22, 3.78, -5.92, 1.16] prices = [i if i > 0 else 0 for i in original_prices] print(prices) # Which is like: def get_price(price: float) -> float: return price if price > 0 else 0 prices = [get_price(i) for i in original_prices] print(prices) # Nesting # Nesting with n loops my_list = [] for x in [20, 40, 60]: for y in [2, 4, 6]: my_list.append(x * y) print(my_list) # Nesting n list comps my_list = [x * y for x in [20, 40, 60] for y in [2, 4, 6]] print(my_list) # A more complicated example: combos = [] for x in [1, 2, 3]: for y in [3, 1, 4]: if x != y: combos.append((x, y)) print(combos) # is equal to: combos = [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y] print(combos) # Note: it may be helpful to break these across lines as above # Nested lists are a common way to create matrices # Remember: _ is a normal variable name, # by convention for discarded or unused vars matrix = [[i for i in range(5)] for _ in range(6)] print(matrix) # %% Set comprehensions """ While the list comprehension in Python is a common tool, you can also create set and dictionary comprehensions. A set comprehension is almost exactly the same as a list comprehension in Python. The difference is that set comprehensions make sure the output contains no duplicates. """ # Using loop for constructing output set input_list = [1, 2, 3, 4, 4, 5, 6, 6, 6, 7, 7] output_set = set() for var in input_list: if var % 2 == 0: output_set.add(var) print("Output Set using for loop:", output_set) # Using Set comprehensions for constructing output set input_list = [1, 2, 3, 4, 4, 5, 6, 6, 6, 7, 7] set_using_comp = {var for var in input_list if var % 2 == 0} print("Output Set using set comprehensions:", set_using_comp) # As always, sets enforce uniqueness quote = "life, uh, finds a way" unique_vowels = {i for i in quote if i in "aeiou"} print(unique_vowels) # A more advanced example: from math import sqrt n = 100 sqrt_n = int(sqrt(n)) no_primes = {j for i in range(2, sqrt_n + 1) for j in range(i * 2, n, i)} print(no_primes) primes = {i for i in range(2, n) if i not in no_primes} print(primes) # %% Dictionary comprehensions """ General form: {key: value for (key, value) in iterable if (key, value satisfy condition)} or across lines: {key: value for (key, value) in iterable if (key, value satisfy condition)} Remember: keys should be unique """ # n and n squared in dict: d = {n: n ** 2 for n in range(5)} print(d) # A nested example: cities = ["Austin", "Tacoma", "Topeka", "Sacramento", "Charlotte"] temps = {city: [0 for _ in range(7)] for city in cities} print(temps) # +++++++++ Cahoot-20.1 # https://mst.instructure.com/courses/58101/quizzes/57262