Python: Choose random word from list then remove it - python

The question is to chooses a random word from a list of words you have defined, and then remove the word from the list. The computer should display a jumble of the word and ask the user to guess what the word is. Once the player has guessed the word, another random word should be selected from the list and the game continues until the list of words is empty.
When I run it, i have an error.
Traceback (most recent call last):
File "F:\Computer Science\Unit 3\3.6\3.6 #5.py", line 21, in <module>
word_jamble (random_word)
File "F:\Computer Science\Unit 3\3.6\3.6 #5.py", line 14, in word_jamble
word = list(word)
TypeError: 'list' object is not callable
This is my program
list = ['mutable', 'substring', 'list', 'array', 'sequence']
from random import shuffle
def word_jamble(word):
word = list(word)
shuffle(word)
print ''.join(word)
from random import choice
random_word = choice(list)
word_jamble (random_word)
user_input = raw_input("What's the word? ")
if user_input == choice(list):
del list[index(choice(list))]

You should change your first variable, list, to something else. It is being confused with the built-in list type, and your list object is of course not callable.

The main problem is the variable's name, list. Its a builtin type constructor's name. When you use say list, it shadows the builtin type's name. Apart from that, you can use pop method, like this, to get the random words out of the list easily
words_list = ['mutable', 'substring', 'list', 'array', 'sequence']
import random
while words_list:
print words_list.pop(random.randrange(len(words_list)))

It means exactly what it says:
TypeError: 'list' object is not callable
It is complaining about
word = list(word)
because at this point,
list = ['mutable', 'substring', 'list', 'array', 'sequence']
has already happened.
Once you make list a name for that particular list, it can no longer be a name for the built-in list class. A name only names one thing at a time.

There are a few basic problems with the code:
list = ['mutable', 'substring', 'list', 'array', 'sequence']
list is the list constructor. You should never name your variables after python keywords.
del list[index(choice(l))]
del is very rarely needed in python. My suggestion is that, if you're a begginner, you should forget about it entirely. The proper way of removing elements from lists is using either list.remove (based on element equality) or list.pop (based on index)
def word_jamble(word):
word = list(word)
shuffle(word)
print ''.join(word)
Here, you're using a function to achieve to distinct tasks: shuffling a word, and printing it. Generally, it's a good practice to make each function perform only a specific task - this leads to more reusable and organized code. Instead of printing the result inside the function, consider returning it, and printing it outside.
from random import shuffle
# some code
from random import choice
It's good practice to keep your imports together, and on the beggining of your program. If you're importing two elements from the same module, you can separate them using a comma:
from random import shuffle, choice
Finally, since you want to repeat the game until there are no words left, you need to use a cycle:
while len(word_list)>0: # can be written simply as "while len(word_list):"
#your code here

Related

How do I call .lower on a class object?

I have a class I've called Earthquake, and it has a location as a string, and a few other parts that aren't important to this question (I don't think).
I've written a function (filter_by_place) that iterates through a list of Earthquakes that I've passed it, and looks for a given word in each Earthquake location string. If the word is found in the Earthquake's location, then it adds that Earthquake to a list. My problem is that it cannot be case sensitive, and I'm trying to make it that way by looking for an all lowercase word in an all lowercase version of the location string.
def filter_by_place(quakes, word):
lst = []
for quake in quakes:
if word.lower in (quake.place).lower:
lst.append(quake)
return lst
I get an error saying "TypeError: argument of type 'builtin_function_or_method' is not itterable"
So, my question is: How do I get that string within the class to become lowercase just for this function so I can search for the word without worrying about case sensitivity?
I've already tried adding
if word.lower or word.upper in quake.place:
inside the for loop, but that didn't work, and I can understand why. Help?
You're getting the error because you're not actually calling the lower string function. I am guessing you're coming from ruby where this wouldn't be required.
Try:
def filter_by_place(quakes, word):
lst = []
for quake in quakes:
if word.lower() in quake.place.lower():
lst.append(quake)
return lst
You need to do word.lower(). You're missing the brackets. Happens all the time :)
Try this
def filter_by_place(quakes, word):
lst = []
for quake in quakes:
if word.lower() in quake.place.lower():
lst.append(quake)
return lst
Because you're using python, you might want to take a look at list comprehensions. You're code would then look something like this
def filter_by_place(quakes, place):
return [quake for quake in quakes if quakes.place.lower() is place]

How to obtain a random string from a list

My class was recently introduced to lists and our task is to randomly obtain a name from the said list, This is the code i have generated
import random
Random1 = random.randint(0,7)
Class_List = ['Noah','Simone','Ji Ho','Thanh','Nathanial','Soo','Mickel','Tuan','Thuy Linh']
print (ClassList[{}].format(Random1))
However i receive this error
Traceback (most recent call last):
File "C:/Users/Mickel/Documents/Python/RPS Tournament/Rock Paper Sissor Tornament.py", line 4, in <module>
print (ClassList[{}].format(Random1))
TypeError: list indices must be integers, not dict
Any solutions?
Python has a very simple method for this: random.choice
import random
class_list = ['Noah','Simone','Ji Ho','Thanh','Nathanial','Soo','Mickel','Tuan','Thuy Linh']
print(random.choice(class_list))
Regarding why your answer isn't working:
print (ClassList[{}].format(Random1))
.format is for interpolating a value into a string - for example"{}".format(5). Obviously this is something different than what you're doing. If you wish to still use your approach, here's how:
Class_List = ['Noah','Simone','JiHo','Thanh','Nathanial','Soo','Mickel','Tuan','Thuy Linh']
Random1 = random.randint(0,len(Class_List))
print (ClassList[Random1])
Use random.choice for this. Read the documentation I've linked.
You are printing a value from the list in a form of an empty dictionary where an index number should be instead. That's why you get an error. But you spelled it wrong anyway. It should be "Class_List", not "ClassList".
As for your questing, personally I would do it this way
#!/usr/bin/python
import random
Class_List = ['Noah','Simone','Ji Ho','Thanh','Nathanial','Soo','Mickel','Tuan','Thuy Linh']
random.shuffle(Class_List)
print (Class_List[0])

Error with Python dictionary: str object has no attribute append

I am writing code in python.
My input line is "all/DT remaining/VBG all/NNS of/IN "
I want to create a dictionary with one key and multiple values
For example - all:[DT,NNS]
groupPairsByKey={}
Code:
for line in fileIn:
lineLength=len(line)
words=line[0:lineLength-1].split(' ')
for word in words:
wordPair=word.split('/')
if wordPair[0] in groupPairsByKey:
groupPairsByKey[wordPair[0]].append(wordPair[1])
<getting error here>
else:
groupPairsByKey[wordPair[0]] = [wordPair[1]]
Your problem is that groupPairsByKey[wordPair[0]] is not a list, but a string!
Before appending value to groupPairsByKey['all'], you need to make the value a list.
Your solution is already correct, it works perfectly in my case. Try to make sure that groupPairsByKey is a completely empty dictionary.
By the way, this is what i tried:
>>> words = "all/DT remaining/VBG all/NNS of/IN".split
>>> for word in words:
wordPair = word.split('/')
if wordPair[0] in groupPairsByKey:
groupPairsByKey[wordPair[0]].append(wordPair[1])
else:
groupPairsByKey[wordPair[0]] = [wordPair[1]]
>>> groupPairsByKey
{'of': ['IN'], 'remaining': ['VBG'], 'all': ['DT', 'NNS']}
>>>
Also, if your code is formatted like the one you posted here, you'll get an indentationError.
Hope this helps!
Although it looks to me like you should be getting an IndentationError, if you are getting the message
str object has no attribute append
then it means
groupPairsByKey[wordPair[0]]
is a str, and strs do not have an append method.
The code you posted does not show how
groupPairsByKey[wordPair[0]]
could have a str value. Perhaps put
if wordPair[0] in groupPairsByKey:
if isinstance(groupPairsByKey[wordPair[0]], basestring):
print('{}: {}'.format(*wordPair))
raise Hell
into your code to help track down the culprit.
You could also simplify your code by using a collections.defaultdict:
import collections
groupPairsByKey = collections.defaultdict(list)
for line in fileIn:
lineLength=len(line)
words=line[0:lineLength-1].split(' ')
for word in words:
wordPair=word.split('/')
groupPairsByKey[wordPair[0]].append(wordPair[1])
When you access a defaultdict with a missing key, the factory function -- in this case list -- is called and the returned value is used as the associated value in the defaultdict. Thus, a new key-value pair is automatically inserted into the defaultdict whenever it encounters a missing key. Since the default value is always a list, you won't run into the error
str object has no attribute append anymore -- unless you have
code which reassigns an old key-value pair to have a new value which is a str.
You can do:
my_dict["all"] = my_string.split('/')
in Python,

TypeError when using replace() from dictionary

First of all: Please keep in mind that I'm very much a beginner at programming.
I'm trying to write a simple program in Python that will replace the consonants in a string with consonant+"o"+consonant. For example "b" would be replaced with "bob" and "d" would be replaced with "dod" (so the word "python" would be changed to "popytothohonon").
To do this I created a dictionary, that contained the pairs b:bob,c:coc,d:dod etc. Then I used the replace() command to read through the word and replace the consonants with their translation in the dictionary. The full piece of code looks like this:
def replacer(text):
consonant='bcdfghjklmnpqrstvwxz'
lexicon={}
for x in range(0,len(consonant)):
lexicon[x]=(consonant[x]),(consonant[x]+'o'+consonant[x])
for i,j in lexicon.items():
text=(text.replace(i,j))
return text
Now, when I try to call this function I get the following error:
Traceback (most recent call last):
File "D:\x\x.py", line 37, in <module>
print(replacer("python"))
File "D:\x\x.py", line 17, in replacer
text=(text.replace(i,j))
TypeError: Can't convert 'int' object to str implicitly
But I'm not using any ints! There's got to be something wrong with the dictionary, because everything works when i make it "by hand" like this:
list={'b':'bob', 'c':'coc', 'd':'dod', 'f':'fof', 'g':'gog', 'h':'hoh'......}
But when I print the "non-hand-made" dictionary everything seems to be in order:
{0: ('b', 'bob'), 1: ('c', 'coc'), 2: ('d', 'dod'), 3: ('f', 'fof')........
What am I doing wrong?
lexicon is a dictionary with integers as keys and tuples as values. when you iterate over it's items, you're getting tuples of the form (integer,tuple). You're then passing that integer and tuple to text.replace as i and j which is why it's complaining. Perhaps you meant:
for i,j in lexicon.values():
...
For this simple replacement, str.replace is fine, but for more complicated replacements, the code will probably be more robust (and possibly execute faster!) if you use re.sub instead.
Also, as pointed out in the comments, for this case, a better data structure would be to use a list:
lexicon = [ (x,'{0}o{0}'.format(x)) for x in chars ]
Now you can build your dict from this list if you really want:
lexicon = dict(enumerate(lexicon))
but there's probably no need. And in this case, you'd iterate over lexicon directly:
for i,j in lexicon:
...
If you're only going to do this once, you could even do it lazily without ever materializing the list by using a generator expression:
lexicon = ( (x,'{0}o{0}'.format(x)) for x in chars )
I guess what you wanted to achieve is lexicon mapping consonant to replacement. It may be done this way:
lexicon = { c: c+'o'+c for c in consonant }
which is equivalent of:
for c in consonant:
lexicon[c] = c+'o'+c
No need for dictionaries this time, just iterate over characters of text, add vovels or consonant+o+consonant to an result array and join it to a string at the end:
def replacer(text):
consonants = set('bcdfghjklmnpqrstvwxz')
result = []
for c in text:
if c in consonants:
result.append(c+"o"+c)
else:
result.append(c)
return "".join(result)
print(replacer("python"))
For advanced users:
def replacer(text):
return re.sub(r"[bcdfghjklmnpqrstvwxz]", r"\g<0>o\g<0>", text)
And to answer "What am I doing wrong?" - dictionaries are useful for arbitrary keys, usually list.append() is preferred from using keys 0-n in a dict. And since you are not interested in a consonant's position, you can iterate over strings directly like this:
for x in consonant:
lexicon[x] = x+"o"+x
no ... your keys in the handmade version are strings ... your kets in the other version are ints ... ints have no replace method

How do I remove entries within a Counter object with a loop without invoking a RuntimeError?

from collections import *
ignore = ['the','a','if','in','it','of','or']
ArtofWarCounter = Counter(ArtofWarLIST)
for word in ArtofWarCounter:
if word in ignore:
del ArtofWarCounter[word]
ArtofWarCounter is a Counter object containing all the words from the Art of War. I'm trying to have words in ignore deleted from the ArtofWarCounter.
Traceback:
File "<pyshell#10>", line 1, in <module>
for word in ArtofWarCounter:
RuntimeError: dictionary changed size during iteration
Don't loop over all words of a dict to find a entry, dicts are much better at lookups.
You loop over the ignore list and remove the entries that exist:
ignore = ['the','a','if','in','it','of','or']
for word in ignore:
if word in ArtofWarCounter:
del ArtofWarCounter[word]
For minimal code changes, use list, so that the object you are iterating over is decoupled from the Counter
ignore = ['the','a','if','in','it','of','or']
ArtofWarCounter = Counter(ArtofWarLIST)
for word in list(ArtofWarCounter):
if word in ignore:
del ArtofWarCounter[word]
In Python2, you can use ArtofWarCounter.keys() instead of list(ArtofWarCounter), but when it is so simple to write code that is futureproofed, why not do it?
It is a better idea to just not count the items you wish to ignore
ignore = {'the','a','if','in','it','of','or'}
ArtofWarCounter = Counter(x for x in ArtofWarLIST if x not in ignore)
note that I made ignore into a set which makes the test x not in ignore much more efficient
See the following question for why your current method is not working:
Remove items from a list while iterating
Basically you should not add or remove items from a collection while you are looping over it. collections.Counter is a subclass of dict, see the following warning in the documentation for dict.iteritems():
Using iteritems() while adding or deleting entries in the dictionary may raise a RuntimeError or fail to iterate over all entries.
Use a counter, traverse the loop backwards (last to first), remove as needed. Loop until zero.

Categories