Angel Fernandez Angel Fernandez - 10 months ago 61
Python Question

using defaultdict in a array in python 2.7

I'm trying to create a dictionary where the same key can have different values from an array. In the past i created a dictionary with positions on each list of the list, but I found a bug where the same key can have more than one value and it's breaking the main code.

my_array = [['a','b','c'],['a','e','d'],['f','g','h']]
my dict = dict([p[0], p[2]] for p in my_array)
my dict = {'a': 'c', 'f': 'h'}
What I need is:
my_dict = {'a': ['c','d'], 'f': 'h'}

I have tried with defaultdict but so far I'm getting TypeError Exception. I have tried initializing it as a string defaultdict(str) and a list defaultdict(list) with no success

my_dict = defaultdict((my_dict[p[0]].append(p[2])) for p in my_array)
my_dict = defaultdict(([p[0], p[2]]).append(p[2]) for p in a_array)

Always getting TypeError exception, suggestions please?

Answer Source

You can't do this with a comprehension/generator expression. Instead, try this:

my_dict = {}
for p in my_array:
    my_dict.setdefault(p[0], []).append(p[2])

You can also do it with a defaultdict if you insist, but it seems like overkill:

my_dict = collections.defaultdict(list)
for p in my_array:

All your values will now be lists, even if they contain only a single item, which doesn't appear to be what you want based on your question. It probably actually is, as it's much easier to deal with values that are always the same type. But if you do want the single values outside of lists, I think the most straightforward way is to post-process after building the dictionary and convert single-item lists back to single values:

for k, v in my_dict.iteritems():  # n.b. just .items() in Python 3
    if len(v) == 1:
        my_dict[k] = v[0]

Otherwise, you end up having to check the type of each value already in the dictionary when you're adding a new one, and convert the value to a list when you go to add the second one.