Reputation:
Let's say I have a list of characters and I want to map each to the number of times it occurs in the list. The following code accomplishes this:
characters = ['a','b','c','a']
d = {}
for ch in characters:
d[ch] = d.get(ch,0) + 1
return d
Now let's say, instead of having each character mapped to the number of times it occurs in the list, I want to map it to a list of 1's, where each 1 represents an occurance in the list. So for example, something like {a:[1,1], b:[1], c:[1]}. I use the same format but it doesn't work. Can someone explain why not?
characters = ['a','b','c','a']
d = {}
for ch in characters:
d[ch] = d.get(ch,[]).append(1)
#print type(d['a'])
return d
I get AttributeError: 'NoneType' object has no attribute 'append', even though a print type(d['a']) returns "list" if I remove the .append() in the for loop. Thanks!
Upvotes: 0
Views: 77
Reputation: 2867
This is my proposed solutions:
characters = ['a','b','c','a']
d = {}
for ch in characters:
d.setdefaultappend(ch, []).append(1)
return d
Upvotes: 0
Reputation: 155
use python dir
function
list
has append method
dist
has no append method
>>> characters = []
>>> d = {}
>>> dir(characters)
['__add__', '__class__', '__contains__', '__delattr__', '__delitem__',
'__delslice__', '__doc__', '__eq__', '__format__', '__ge__',
'__getattribute__', '__getitem__', '__getslice__', '__gt__', '__hash__',
'__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__',
'__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__',
'__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__',
'__setslice__', '__sizeof__', '__str__', '__subclasshook__', 'append',
'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
>>> dir(d)
['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__',
'__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
'__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__',
'__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get',
'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop',
'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys', 'viewvalues']
Upvotes: -1
Reputation: 2122
The line d[ch] = d.get(ch,[]).append(1)
sets d[ch]
to the value returned by append
function which is None. Do this instead:
d[ch] = d.get(ch, [])
d[ch].append(1)
Upvotes: 0
Reputation: 133574
characters = ['a','b','c','a']
d = {}
for ch in characters:
d[ch] = d.get(ch,[]).append(1)
#print type(d['a'])
return d
dict.get
returns the value at the key ch
and if it doesn't exist it returns the default value you provided, the list []
you have created. Anyway, I think you may be confused because d.get
doesn't set any values, it only returns one. Then you are appending 1
to this list. .append
is an inplace operation so it won't return the post-appended list as you may have expected, it simply returns None
to signify that it is not supposed to be used the way you have. What you could do instead is
d.setdefault(ch, []).append(1)
Which does what you would expect ;)
To avoid this crazy syntax you could make use of a collections.defaultdict
like so:
d = defaultdict(list)
d[ch].append(1)
which looks much cleaner
Upvotes: 2
Reputation: 82028
You're assigning the value of d[ch]
to the return value of [].append
. Think of it this way your code is the equivalent of
tmp = d.get(ch,[])
d[ch] = tmp.append(1)
Try this instead:
d[ch] = d.get(ch,[])
d[ch].append(1)
Upvotes: 0