Here are our solutions for the day 20 exercises in the 30 Days of Python series. Make sure you try the exercises yourself before checking out the solutions!

1) Use map to call the strip method on each string in the following list. Print the lines of the nursery rhyme on different lines in the console.

humpty_dumpty = [
	"  Humpty Dumpty sat on a wall,  ",
	"Humpty Dumpty had a great fall;     ",
	"  All the king's horses and all the king's men ",  
	"    Couldn't put Humpty together again."
]

First, let's try to tackle this by defining a separate function to perform the strip on a given line. I'm going to call mine line_stripper, but you can call it whatever you like.

def line_stripper(line):
	return line.strip()

Now we can write our map call. When calling map, we need to first pass in the function we want to call, and then we pass in the iterables we want to grab arguments from. In this case, we just have a single iterable: humpty_dumpty.

We can then unpack the map object and pass it to print.

def line_stripper(line):
	return line.strip()


humpty_dumpty = [
	"  Humpty Dumpty sat on a wall,  ",
	"Humpty Dumpty had a great fall;     ",
	"  All the king's horses and all the king's men ",  
	"    Couldn't put Humpty together again."
]

print(*map(line_stripper, humpty_dumpty), sep="\n")

If you prefer, you could also use a for loop to print the values.

Instead of defining this line_stripper function, we could also use a lambda expression:

humpty_dumpty = [
	"  Humpty Dumpty sat on a wall,  ",
	"Humpty Dumpty had a great fall;     ",
	"  All the king's horses and all the king's men ",  
	"    Couldn't put Humpty together again."
]

print(*map(lambda line: line.strip(), humpty_dumpty), sep="\n")

But we could also use the methodcaller function from the operator module if we didn't want to define function using lambda.

from operator import methodcaller

humpty_dumpty = [
	"  Humpty Dumpty sat on a wall,  ",
	"Humpty Dumpty had a great fall;     ",
	"  All the king's horses and all the king's men ",  
	"    Couldn't put Humpty together again."
]

print(*map(methodcaller("strip"), humpty_dumpty), sep="\n")

Any of these approaches is perfectly fine.

2) Below you'll find a tuple containing several names. Use a list comprehension with a filtering condition so that only names with fewer than 8 characters end up in the new list. Make sure that every name in the new list is in title case.

names = ("bob", "Christopher", "Rachel", "MICHAEL", "jessika", "francine")

First let's just create a comprehension to turn the names to lowercase. We can add the filtering condition once we know it works.

names = ("bob", "Christopher", "Rachel", "MICHAEL", "jessika", "francine")
names = [name.title() for name in names]

A quick print of names shows that we don't have any issues, so now we need to add our filter. In this case, we want to check whether or not the name contains less than 8 characters.

We can find out how many characters are in a string using the len function, and we can compare the result against 8 using <.

names = ("bob", "Christopher", "Rachel", "MICHAEL", "jessika", "francine")
names = [name.title() for name in names if len(name) < 8]

If you're curious as to how we replicate something like this with map and filter, we can pass the result of calling filter to map like this:

from operator import methodcaller

names = ("bob", "Christopher", "Rachel", "MICHAEL", "jessika", "francine")
names_title = map(methodcaller("title"), filter(lambda name: len(name) < 8, names))

For situations like this where we need to perform a modification and we need to do some filtering, the comprehension syntax is usually a lot neater and easier to understand.

3) Use filter to remove all negative numbers from the following range: range(-5, 11). Print the remaining numbers to the console.

We can actually do this on in one line if we want to like so:

print(*filter(lambda number: number >= 0, range(-5, 11)))

Here we're saying that for every number in range(-5, 11), keep the number if it's greater than 0. Then we're unpacking the filter object using *, so that we get access to the values we've kept.

This is extremely succinct; however, in this case, I think it makes a lot of sense to create a separate function for our filter predicate.

def is_positive(number):
	return number >= 0


print(*filter(is_positive, range(-5, 11)))