milesabc123
milesabc123

Reputation: 85

How do I turn a series of IF statements into a Pythonic code line?

I am trying to improve my list comprehension capabilities. I would like to turn the following into a Pythonic code line:

# Sample sentence
sample_sentence = "Once upon a time, three people walked into a bar, Once upon a time, three people walked into a bar"

# Empty list to hold words from sentence
words = []

# Empty lists to hold longest and shortest items
longest = []
shortest = []

# Pythonic method to split sentence into list of words
words = [c for c in sample_sentence.split()]

# Non-Pythonic routine to find the shortest and longest words
for i in words:
    if len(i) <= shortest_len:
        # shortest = [] # Reset list
        shortest.append(i)
    if len(i) >= longest_len:
        longest.append(i)

print(f"Shortest item: {', '.join(shortest)}")
print(f"Longest item: {', '.join(longest)}")

I have tried creating a Pythonic version of the non-Pythonic routine to find the shortest and longest words:

shortest = [i for i in words if len(i) <= shortest_len: shortest.append(i) ]
print(shortest)
longest = [i for i in words if len(i) >= longest_len: longest.append(i)]
print(longest)

But it gets an invalid syntax error.

How can I construct the above two code lines and also is it possible to use a single Pythonic line to combine the two?

Upvotes: 1

Views: 106

Answers (6)

Sorin Dragan
Sorin Dragan

Reputation: 540

This is an one-liner to find the length of every word in your sentence and sort them from the shortest to the longest:

words_len = sorted(list(set([(c, len(c)) for c in sample_sentence.split()])), key=lambda t: t[1])

Or as I was pointed out in the comments, you can achieve the same by doing this:

words = sorted(list(set(sample_sentence.split())), key=len)
print(f"shortest: {words[0]}\nlongest: {words[-1]}") 

Upvotes: 0

First of all, you need to define shortest_len and longest_len somewhere. You can use this:

shortest_len = min([len(word) for word in words])
longest_len = max([len(word) for word in words])

shortest = [word for word in words if len(word) == shortest_len]
longest = [word for word in words if len(word) == longest_len]

It is possible to combine the two lines into

shortest, longest = [word for word in words if len(word) == shortest_len], [word for word in words if len(word) == longest_len]

If you want to go really crazy, you can compact it as far as this:

sample_sentence = "Once upon a time, three people walked into a bar, Once upon a time, three people walked into a bar"

print(f"Shortest item: {', '.join([word for word in [c for c in sample_sentence.split()] if len(word) == min([len(word) for word in words])])}")
print(f"Longest item: {', '.join([word for word in [c for c in sample_sentence.split()] if len(word) == max([len(word) for word in words])])}")

or even join these two into one print to get a one-liner:

sample_sentence = "Once upon a time, three people walked into a bar, Once upon a time, three people walked into a bar"

print(f"Shortest item: {', '.join([word for word in [c for c in sample_sentence.split()] if len(word) == min([len(word) for word in words])])}\nLongest item: {', '.join([word for word in [c for c in sample_sentence.split()] if len(word) == max([len(word) for word in words])])}")

But, as already pointed out by @big_bad_bison, the shortest solution is not always the same as the best solution and the readability of your code (for yourself, over months or years; or for others, if you ever need to work in a team or maybe ask for help) is much more important.

Many one-liners are not cleanly Pythonic because they make for a line of code that is too long. PEP 8 - Style Guide for Python Code (definitely suggested reading!) stays clearly:

Limit all lines to a maximum of 79 characters.

Upvotes: 0

Rishin Rahim
Rishin Rahim

Reputation: 655

An alternative code to get the shortest and longest words:

sample_sentence = "Once upon a time, three people walked into a bar, Once upon a time, three people walked into a bar"

my_list = list(set([(token,len(token)) for token in sample_sentence.split()]))
longest_word = ', '.join(i[0] for i in my_list if i[1]==max([x[1] for x in my_list]))
shortest_word = ', '.join(i[0] for i in my_list if i[1]==min([x[1] for x in my_list]))
print(f"longest words: {longest_word}")
print(f"shortest words: {shortest_word}")

output

longest words: people, walked
shortest words: a

Upvotes: 0

big_bad_bison
big_bad_bison

Reputation: 1015

Don't make the mistake of thinking that everything has to be a clever one-liner. It is better to write code that you will be able to look at in the future and know exactly what it will do. In my opinion, this is a very Pythonic way to write your script. Yes there are improvements that could be made, but don't optimize if you don't have to. This script is reading two sentences, if it was reading entire books then we can make improvements.

As said in the comments, everyone has their own definition of "Pythonic" and their own formatting. Personally, I don't think you need the comments when it is very clear what your code is doing. For instance, you don't need to comment "Sample Sentence" when your variable is named sample_sentence.

sample_sentence = "Once upon a time, three people walked into a bar, Once upon a time, three people walked into a bar"

words = sample_sentence.split()
words.sort(key=len)

short_len = len(words[0])
long_len = len(words[-1])

shortest_words = [word for word in words if len(word) == short_len]
longest_words = [word for word in words if len(word) == long_len]

print(f"Shortest item: {', '.join(shortest_words)}")
print(f"Longest item: {', '.join(longest_words)}")

Upvotes: 1

TheEagle
TheEagle

Reputation: 5982

To resolve the SyntaxError, you must just remove the : shortest.append(i) and : longest.append(i). The lists will be as expected, then.

is it possible to use a single Pythonic line to combine the two ?

No, it is not possible to build up both lists on one line. (Except that you can of ccourse put both list constructions on one line:

shortest = [i for i in words if len(i) <= shortest_len: shortest.append(i)]; longest = [i for i in words if len(i) >= longest_len: longest.append(i)]

). But I don't think that was your goal …

Upvotes: 0

kuro
kuro

Reputation: 3226

Try this for your list comprehension case to resolve the syntax error -

shortest = [i for i in words if len(i) <= shortest_len]
print(shortest)
longest = [i for i in words if len(i) >= longest_len]
print(longest)

Also instead of words = [c for c in sample_sentence.split()] you can use words = sample_sentence.split()

Upvotes: 0

Related Questions