-4

I'm learning list comprehensions in Python. I was to append letters from a list of words and form a new list but without duplicates. This is what I'm trying:

wordlist = ['cat','dog','rabbit']

letterlist = [aletter for aword in wordlist  for aletter in aword if aletter not in letterlist]

print letterlist

I'm getting the following error:

Traceback (most recent call last):
  File "training.py", line 5, in <module>
    letterlist = [aletter for aword in wordlist  for aletter in aword if aletter not in letterlist]
NameError: name 'letterlist' is not defined

What am I doing wrong ?

zondo
  • 19,901
  • 8
  • 44
  • 83
Batman
  • 39
  • 2
  • 8
  • Yes i'm aware that sets can remove duplicates but I'm looking for a solution that doesn't involves sets. – Batman Mar 06 '16 at 23:55
  • Also see [here](http://stackoverflow.com/questions/17774394/python-list-comprehension-list-sub-items-without-duplicates), [here](http://stackoverflow.com/questions/29512152/avoid-inserting-duplicates-into-python-list-with-comprehension), and [here](http://stackoverflow.com/questions/480214/how-do-you-remove-duplicates-from-a-list-in-python-whilst-preserving-order), as well as many other results from a basic Google search. – TigerhawkT3 Mar 07 '16 at 00:13

4 Answers4

4

letterlist is not defined until the list comprehension is finished. Therefore, you can't reference it inside itself. A function can reference itself only because the function is not called until after it's defined, but a list comprehension is being executed as part of the definition, so it can't reference itself. A possible way to do it would be to define the list without the test, and then remove the duplicates:

letterlist = list(set(["".join(wordlist)]))  # Modified from idjaw's answer

Using set() makes it a list (which removes the duplicates), and using list converts it back to a list.

If you really don't want to use a set, then using a list comprehension is probably not the best way to go. You could use a for loop like this:

letterlist = []
for char in "".join(wordlist):
    if char not in letterlist:
        letterlist.append(char)
zondo
  • 19,901
  • 8
  • 44
  • 83
  • Then this should work right ? wordlist = ['cat','dog','rabbit'] letterlist = [] print [aletter for aword in wordlist for aletter in aword if aletter not in letterlist] But its not removing duplicates ! – Batman Mar 06 '16 at 23:54
  • @Batman: That's because you aren't modifying `letterlist` when you create the list comprehension. Try the `set` way that I gave above. – zondo Mar 06 '16 at 23:55
  • Got it ! This implies that list comprehensions are only good for a very specific use case , when you want to append stuff without performing any case checking. – Batman Mar 07 '16 at 00:03
  • @Batman: It is perfectly okay to use list comprehensions with case checking, but the case checking just can't involve the list that you are creating. For example, you could find a list of the numbers from one to 40 that have whole number square roots with `[x for x in range(1, 41) if not ((x ** 0.5)%1)]` That definitely has case checking, but it doesn't involve the list that is currently being created. – zondo Mar 07 '16 at 00:05
1

If you simply want to get rid of duplicates, you might want to utilize set().

x = [1,1,14,4,47,7,7,14,47]
list(set(x))
Debosmit Ray
  • 5,228
  • 2
  • 27
  • 43
0

In this particular scenario list comprehension may not be the route to take. Just take the for loops and put them outside and append elements to your list as you go so that when you check the list, it does exist. In any case the complexity of the algorithm you are using is going to be quite horrendous :/

Mixone
  • 1,327
  • 1
  • 13
  • 24
0

This can be much simpler if you do this by making a string from your list, then calling set, you get all unique characters:

set(''.join(wordlist))

And if it has to be a list, just call list on it:

list(set(''.join(wordlist)))

Information on set and join

idjaw
  • 25,487
  • 7
  • 64
  • 83