-2

I want to build a list of words. For each word on each line check to see if the word is already in the list and if not append it to the list. When the program completes, sort and print the resulting words in alphabetical order. But when I add a string to the list, it shows "argument of type 'NoneType' is not iterable". What' worry?

    fh = ("But soft what light through yonder window breaks"
    "It is the east and Juliet is the sun"
    "Arise fair sun and kill the envious moon"
    "Who is already sick and pale with grief")
    lst = list()
    for line in fh:
        words = line.split()
        for word in line:
                if word not in lst:
                    lst = lst.append(word)
    lst.sort()
    print lst
Idos
  • 14,036
  • 13
  • 48
  • 65
M.r
  • 13
  • 3
  • 2
    1) Try printing `fh`; it's not what you think it is. 2) Why do you do `words = line.split()` and then do nothing with `words`? Is `for word in line:` supposed to be `for word in words:`? 3) What do you expect `lst = lst.append(word)` to do? 4) To do this efficiently, you should use a [`set`](https://docs.python.org/2/library/stdtypes.html#set-types-set-frozenset). – PM 2Ring Jan 02 '16 at 14:41

3 Answers3

2

When you put two string literals next to each other, you get one string:

>>> 'hi' 'there'
'hithere'

The whitespace between them doesn't affect this. This means that for line in fh: is iterating over each character, not each line, producing unexpected results. You have a few options to fix this.

With a triple-quoted string and splitlines():

fh = ("""But soft what light through yonder window breaks
It is the east and Juliet is the sun
Arise fair sun and kill the envious moon
Who is already sick and pale with grief""")
fh = fh.splitlines()

Result:

>>> fh[0]
'But soft what light through yonder window breaks'

Or with a list or tuple:

fh = ("But soft what light through yonder window breaks",
"It is the east and Juliet is the sun",
"Arise fair sun and kill the envious moon",
"Who is already sick and pale with grief")

Result:

>>> fh[0]
'But soft what light through yonder window breaks'

Then you split() the line and save that, but you forgot to use it. for word in line: should be for word in words: to iterate over the new object. Alternatively, you could keep that line the same and instead change the line above it (words = line.split()) to line = line.split().

Then you have one more problem: append() does its operation in-place and returns None. This means you simply call that method and it'll do what it says, without the need for reassigning a reference. If you do that, lst would quickly point to None, and you don't want that. Do this instead:

lst.append(word)
TigerhawkT3
  • 44,764
  • 6
  • 48
  • 82
1

Well, fh is a single string, and python wouldn't know how to divide it by lines like you wish. You should try adding commas (or triple-quotes i.e. """):

fh = ("But soft what light through yonder window breaks",
    "It is the east and Juliet is the sun",
    "Arise fair sun and kill the envious moon",
    "Who is already sick and pale with grief")

Which will allow you to get:

>>> fh
('But soft what light through yonder window breaks', 
'It is the east and Juliet is the sun',
'Arise fair sun and kill the envious moon',
'Who is already sick and pale with grief')

After doing so, you may use for line in fh correctly, and then you will probably want to use for word in words instead of for word in line which doesn't make a lot of sense here. This will allow you to iterate over all the words of every line in your text.

In addition, .append() returns None (it is changing the list in-place), so assigning it to a variable is useless in this case. So to remedy this you should probably create a different list and use .append() to it.

Also, speaking generally lst = lst.append(word) doesn't make any sense (even if it "worked"), what are you trying to accomplish with this?

Idos
  • 14,036
  • 13
  • 48
  • 65
0

I will try to help you out.

First, the quality of the question could be better. I think you should try to provide some rationale to your snippet, that way anyone responding could help you by improving not only your solution, but also the thinking behind it (making you a better coder).

Second, this problem has already been solved with lots of good explanations around the web. Check out e.g. item frequency count in python which has a fantastic number of clever solutions.

Third, and this is perhaps the part that you expected, your question shows both that you need to improve your understanding of Python syntax, functionality and general algorithmic thinking. Let me elaborate.

Python Syntax and Functionality

Many of the other answers highlight that the way you are using fh is not very good. Typically, you would have a multiline string written like this in Python:

fh = '''this is the first row
second row
third row'''

Other notable examples of where you would gain from having better understanding of the syntax and functionality of Python is e.g. list comprehension, builtin types and so on. Walk through the is the Python tutorial. Dig in to it, it is very useful!

Algorithmic Thinking

Usually, when I see code such as yours, I try to figure out if the problem is lack of understanding/knowledge of the tool (in this case Python), or of the solution itself. In you case, I think it is a bit of both.

When it comes to the solution, what many experienced coders do (or at least did in the beginning of their careers), is to work out how they intend to solve the problem. A typical experienced coder would check their toolbox to see what would work, and then apply it.

I would solve the problem by using a set use the set datatype to solve this problem. Sets are pretty convenient in most cases, and are well described in the area of discrete mathematics. Check out the book Discrete Mathematics and Its Applications by Rosen, which covers that and a whole bunch of other stuff that you will find useful in the future. (You can probably find a lot of online resources describing sets, but that book is the reference to the area of discrete mathematics. I recommend getting it.)

Because sets are so convenient, Python naturally has builtin support for it. Again, the Python tutorial comes to the rescue, check out the section on sets.

Possible Solution

So, what could a possible solution look like? I would do the following:

  1. Make sure that everything is in a multiline string.
  2. Split the string into a list.
  3. Create a set based on the list content.
  4. Convert back into a list so that it can be sorted.
  5. Sort.
  6. Print.

None of this requires any for or ifstatements, and uses a lot of the builtin functionality of the language.

Hope this advice will help you onwards!

Community
  • 1
  • 1
David Pettersson
  • 358
  • 2
  • 11