Day 18 of 100 - List Comprehensions and Generators Day 3 of 3

List Comprehensions and Generators Day 3 of 3

Day 18 of 100

This challenge was a lot of fun. I had heard of list comprehensions and generators in other videos and podcasts but this was the first time I was able to use them and understand how they might transform my code. I think list comprehensions should be used strategically because they do make the code a little more difficult to read but overall, they are a very fun tool to use. I was less enthusiastic about generators; I understand what they are used for and how how they might optimize code. I just haven't worked with large enough data sets that might take advantage of the speed improvements they offer.

Day 1 of the challenge were the introductory videos. The code challenge for day 2 was to write two functions for a list of names using list comprehensions and generators. The names were stored as a lowercase string and the first function was to use a list comprehension to return a list of names in title case. The second function was to use a generator to take the list of names and return a list of first names that can then be used to make a random pairing of people. Here is the code I came up with (with less help that the previous challenges):

import random


NAMES = ['arnold schwarzenegger', 'alec baldwin', 'bob belderbos',
         'julian sequeira', 'sandra bullock', 'keanu reeves',
         'julbob pybites', 'bob belderbos', 'julian sequeira',
         'al pacino', 'brad pitt', 'matt damon', 'brad pitt']

# write a list comprehension to convert the names to title case
print([name.title() for name in NAMES])

# write a list comprehension to reverse the order of the names in the list
print([' '.join(reversed(name.split())) for name in NAMES])


def generate_pairs(names):
    first_names = []
    [first_names.append(str.split(name)[0]) for name in names]
    name_pairs = []
    while len(first_names) > 1:
        name1 = random.choice(first_names)
        first_names.remove(name1)
        name2 = random.choice(first_names)
        first_names.remove(name2)
        pair = (name1.title(), name2.title())
        name_pairs.append(pair)
    for pair in name_pairs:
        yield pair

pair = generate_pairs(NAMES)

for i in pair:
    print(f'{i[0]} is paired with {i[0]}')

I can already see room for improvement in the second function. When I looked at the solution code, I also removed the names from the list once they were used in a pair while the solution just created pairs, without removing the name from the list.

The third day of the challenge was to complete some Pybites and I chose one about parsing lists (#5). The challenge was to use list comprehensions and generators to write three more functions for the list of names. The first function was to remove duplicates from the list and returen each name in title case. I couldn't get a list comprehension to work with both the for loop and conditional, which I don't know if possible. The solution used a list comprehension to call the list() method while iterating over the list, which I didn't think would remove duplicates, but it did.

The second function was to sort the list in descending order by surname. I was able to solve this by splitting the list of strings to a list of tuples and then used a lamba function to sort the list. I will admit that I am not entirely sure how the lamda function works but I was able to get it to sort the list correctly.

The third function was to return the shortest first name in the list. I used the len() method to calculate the length of the name being passed in and store it in a variable. Then compare the length of each subsequent variable to the one stored in the variable. Overall, a great challenge!

NAMES = ['arnold schwarzenegger', 'alec baldwin', 'bob belderbos',
         'julian sequeira', 'sandra bullock', 'keanu reeves',
         'julbob pybites', 'bob belderbos', 'julian sequeira',
         'al pacino', 'brad pitt', 'matt damon', 'brad pitt']


def dedup_and_title_case_names(names):
    """Should return a list of title cased names,
       each name appears only once"""
    final_list = []
    for name in names:
        if name.title() not in final_list:
            final_list.append(name.title())
    return final_list


def sort_by_surname_desc(names):
    """Returns names list sorted desc by surname"""
    names = dedup_and_title_case_names(names)
    desc_names = []
    for name in names:
        f_name, l_name = name.split()
        desc_names.append((f_name, l_name))
    desc_names.sort(key=lambda x: x[1], reverse=True)
    final_list = []
    for name in desc_names:
        final_list.append(f'{name[0]} {name[1]}')
    return final_list


def shortest_first_name(names):
    """Returns the shortest first name (str).
       You can assume there is only one shortest name.
    """
    names = dedup_and_title_case_names(names)
    shortest_name = (names[0], len(names[0]))
    for name in names:
        if len(name) < shortest_name[1]:
            shortest_name = (name, len(name))
    f_name = shortest_name[0].split()
    return f_name[0]