Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python

Better way to solve this Python Code Challenge?

It took me awhile to solve this Code Challenge. Finally did (yay!) but I have a feeling my solution isn't very elegant. Suggestions welcome!

def word_count(my_string):
  my_string = my_string.lower()
  word_list = my_string.split()
  word_dict = {}
  count = 0
  for word in word_list:
    if word in word_dict:
      count = word_dict[word]
      count += 1
      word_dict.update({word: count})
    else:
      word_dict[word] = 1
  return word_dict

4 Answers

Hello, Ryan! I wouldn't say there's a necessarily better way, but you can make the whole function less verbose. I'll add comments to your code first:

def word_count(my_string):
  my_string = my_string.lower()
  word_list = my_string.split()
  word_dict = {}
  count = 0 # You don't really need this outside of the for loop
  for word in word_list:
    if word in word_dict:
      count = word_dict[word] # Instead of doing all of this
      count += 1 # you can increment the value for that key
      word_dict.update({word: count}) # directly - word_dict[word] += 1
    else:
      word_dict[word] = 1
  return word_dict

So that would turn into:

def word_count(my_string):
  my_string = my_string.lower()
  word_list = my_string.split()
  word_dict = {}
  for word in word_list:
    if word in word_dict:
      word_dict[word] += 1
    else:
      word_dict[word] = 1
  return word_dict

If you want to make it even shorter, you can get rid of the word_list variable and iterate over the return value of the chained .lower().split() method call:

def word_count(my_string):
  word_dict = {}
  for word in my_string.lower().split():
    if word in word_dict:
      word_dict[word] += 1
    else:
      word_dict[word] = 1
  return word_dict

Hi Ryan,

You can increment the count in your if block like this: word_dict[word] += 1

This would grab the current count for that key, add one to it and store it back in that same key.

This can replace the 3 lines you have in your if block.

You can then remove the count initialization before the for loop.

Chris Shaw
Chris Shaw
26,676 Points

Hi Ryan,

Going off Jason's answer which is the same thought process I had you can shorten your code all the way down to...

def word_count(my_string):
  word_dict = {}

  for word in my_string.split():
    if word in word_dict:
      word_dict[word] += 1
    else:
      word_dict[word] = 1

  return word_dict
Kenneth Love
STAFF
Kenneth Love
Treehouse Guest Teacher

Since we talked about this in work chat, I'll post my two alternate solutions. Let's assume this string for all examples:

sentence = "If the facts don't fit the theory change the facts"

Using Counter

So Python has this library named collections that stores a lot of alternate collection types. One of those is Counter which, well, counts things.

from collections import Count

def word_count(my_string):
    words = my_string.lower().split()
    counts = Counter(words)
    return counts
>>> output = word_count(sentence)
Counter({'if': 1, 'the': 3, ...})

What's really awesome about Counter, though is being able to do this:

>>> output.most_common(1)
[('the', 3)]

Using setdefault

Python's dict object has a weird (to me) method called setdefault() that let's you set a default value if the dict doesn't have the key you want. Otherwise it returns the value of the key. Say:

>>> my_dict = {'a': 5}
>>> my_dict.setdefault('a', 10)
5
>>> my_dict.setdefault('b', 10)
10
>>> my_dict
{'a': 5, 'b', 10)

So you can use that for word_count()

def word_count(my_string):
    words = my_string.lower().split()
    counter = {}
    for word in words:
        counter[word] = counter.setdefault(word, 0) + 1
    return counter

The counter[word] = counter.setdefault(word, 0) + 1 line trips some people up. We're setting the default to 0 and then incrementing it by 1. Basically we've negating the try/except that's needed for the usual approach.


So why didn't I teach either of these methods? They're way more special-case than using try/exceptand.get()` and the like. I'd rather you have common scenario tools than wizzbang special effect tools. But, I guess you can now consider yourself taught these nifty little tools. Be sure to check out collections if you want more neat tools.

Thank you sir! :)

Ken Alger
Ken Alger
Treehouse Teacher

Mr. Love;

That is too cool. Didn't know about that in Python.

Mr. Carson;

It is also pretty cool to see you on here sharing the same "struggles" the rest of us have.

Keep up the awesome content, gentlemen.

Ken