Python dictionary that maps strings to a set of strings?
Solution 1
set.add()
does not return a new set
, it modifies the set
it is called on. Use it this way:
word_dict = dict()
word_dict["foo"] = set()
word_dict["foo"].add("baz")
word_dict["foo"].add("bang")
Also, if you use a for
loop to iterate over a dict, you are iterating over the keys:
for key in word_dict:
print key, word_dict[key]
Alternatively you could iterate over word_dict.items()
or word_dict.iteritems()
:
for key, value in word_dict.items():
print key, value
Solution 2
from collections import defaultdict
word_dict = defaultdict(set)
word_dict['banana'].add('yellow')
word_dict['banana'].add('brown')
word_dict['apple'].add('red')
word_dict['apple'].add('green')
for key,values in word_dict.iteritems():
print "%s: %s" % (key, values)
Solution 3
When you say word_dict["foo"].add("baz")
, you are adding 'baz' to the set word_dict["foo"].
The function returns None
-- updating the set is a side-effect. So
word_dict["foo"] = word_dict["foo"].add("baz")
ultimately sets word_dict["foo"]
to None
.
Just word_dict["foo"].add("baz")
would be correct.
In the second scenario, when you say
for key, value in word_dict:
you run into an error because the correct syntax is
for key in word_dict:
to loop over just the keys in word_dict
. In this situation, you want
for key,value in word_dict.iteritems():
instead.
Solution 4
Try:
word_dict = dict()
myset = set()
myset.add("bar")
word_dict["foo"] = myset
myset.add("bang")
word_dict["foo"] = myset
for key in word_dict:
print key, word_dict[key]
It looks like standard dictionary iterator returns only key
but not tuple.
Proof:
>>> d = { 'test': 1 }
>>> for k, v in d: print k, v
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack
>>> for k in d: print d[k]
...
1
Solution 5
The problem is this:
word_dict["foo"] = word_dict["foo"].add("baz")
When you call word_dict["foo"].add("baz")
, you're mutating the set that word_dict["foo"]
refers to, and that operation returns None
. So reading your statement right to left, you're adding "baz" to the set refered to by word_dict["foo"]
, and then setting the result of that operation (that is, None
) to word_dict["foo"]
.
So, to make this work as you expect, just remove word_dict["foo"] =
from your statement.
Dictionaries iterate on their keys by default, hence the ValueError you try this:
for key, value in word_dict:
What's happening here is that iterating on word_dict is returning a key only (say, "foo"), which you're then trying to unpack into the variables key
& value
. Unpacking "foo" gives you "f", "o", & "o", which is one value too many to fit into two variables, and hence your ValueError.
As others have stated, what you want is to iterate on the dictionary's key-value pairs, like so:
for key, value in word_dict.iteritems ():
Ellie P.
I'm a CS student and usability geek working on a Cocoa research project.
Updated on July 09, 2022Comments
-
Ellie P. almost 2 years
I would like to be able to make a Python dictionary with strings as keys and sets of strings as the values. E.g.:
{ "crackers" : ["crunchy", "salty"] }
It must be a set, not a list.However, when I try the following:
word_dict = dict() word_dict["foo"] = set() word_dict["foo"] = word_dict["foo"].add("baz") word_dict["foo"] = word_dict["foo"].add("bang")
I get:
Traceback (most recent call last): File "process_input.py", line 56, in <module> test() File "process_input.py", line 51, in test word_dict["foo"] = word_dict["foo"].add("bang") AttributeError: 'NoneType' object has no attribute 'add'
If I do this:
word_dict = dict() myset = set() myset.add("bar") word_dict["foo"] = myset myset.add("bang") word_dict["foo"] = myset for key, value in word_dict: print key, print value
I get:
Traceback (most recent call last): File "process_input.py", line 61, in <module> test() File "process_input.py", line 58, in test for key, value in word_dict: ValueError: too many values to unpack
Any tips on how to coerce Python into doing what I'd like? I'm an intermediate Python user (or so I thought, until I ran into this problem.)
-
visual_learner over 14 years+1 doesn't directly answer the question but can certainly make the OP's life easier here.
-
visual_learner over 14 yearsAlternately,
for key, value in word_dict.iteritems():
is a bit longer, but nicer on the access ofkey
andvalue
IMHO. -
DrColossos over 12 years+1 didn't know that.. I had the same problem as the OP and this is very nice and IMO more readable than the accepted answer.
-
zvi over 4 yearsPython 3 renamed:
dict.iteritems()
to:dict.items()