0

I have a list of lists:

[['a', 1],['b', 2]['c', 3]['c', 1]['c', 9]['d', 8]['d', 4]]

I want to make a dictionary with :

{ a:1, b:2, c:[3,1,9],d:[8,9]}

I have tried the following:

count = 0
sw_fd_dict = {}
value_list =[]  
sw_fd_list2 = [['a', 1],['b', 2],['c', 3],['c', 1],['c', 9],['d', 8],['d', 4]]
while count < len(sw_fd_list2):
    try:
        # to check for repeated keys like "c"
        if sw_fd_list2[count][0] != sw_fd_list2[count-1][0]: 
            sw_fd_dict[sw_fd_list2[count][0]] = sw_fd_list2[count][1]

        elif sw_fd_list2[count][0] == sw_fd_list2[count-1][0]:
            value_list.append(sw_fd_list2[count-1][1])
            value_list.append(sw_fd_list2[count][1])
            sw_fd_list2[count][1] =value_list
            sw_fd_dict[sw_fd_list2[count][0]] = sw_fd_list2[count][1]

      except Exception as e:
          print str(e)
      count += 1
print sw_fd_dict

Is there a better way to do this?

Jon Clements
  • 138,671
  • 33
  • 247
  • 280
Nijesh
  • 49
  • 8
  • 1
    It makes much more sense (less special cases) to use single element lists for the values of `a` and `b` instead of just the element. – John La Rooy Aug 15 '14 at 06:30

4 Answers4

3

This is a shorter approach:

result = {}
for (key, value) in the_list:
    result.setdefault(key, []).append(value)

setdefault returns the value (like get) but sets it first if it's not present. (defaultdict also works fine here.)

On rereading the question, if you really want the single numbers to not be lists, you can put in some more conditions. I edited this to use a set rather than checking whether the existing value was appendable, in order to be 'safe' in case your values are collections rather than numbers.

result = {}
seen = set()
for (key, value) in the_list:
    if key not in result:
        result[key] = value
    elif key not in seen:
        result[key] = [result[key], value]
        seen.add(key)
    else:
        result[key].append(value)

Or, a nice way of converting the defaultdict-style answer to the one with individual numbers not in lists:

result = {
    key: value[0] if len(value) == 1 else value
    for key, value in result.items()}
Jason S
  • 13,538
  • 2
  • 37
  • 42
2

You can use defaultdict in the collections package:

from collections import defaultdict
sw_fd_dict = defaultdict(list)
sw_fd_list2 =  [['a', 1],['b', 2], ['c', 3], ['c', 1], ['c', 9], ['d', 8], ['d', 4]]

for key, val in sw_fd_list2:
    sw_fd_dict[key].append(val)

sw_fd_dict

Out[8]: defaultdict(<type 'list'>, {'a': [1], 'c': [3, 1, 9], 'b': [2], 'd': [8, 4]})

Then you convert it to a traditional dict:

dict(sw_fd_dict)
Out[9]: {'a': [1], 'b': [2], 'c': [3, 1, 9], 'd': [8, 4]}

EDIT: Quentin THEURET pointed out that I didn't replicate the exact results you want. Thanks to his comment, I've noticed that you require the single value to be an integer on its own, instead wrapped in a list. You can then perform some post-processing:

d = dict(sw_fd_dict)
for k in d.keys():
    if len(d[k]) == 1:
        d[k] = d[k][0]
d
Out[15]: {'a': 1, 'b': 2, 'c': [3, 1, 9], 'd': [8, 4]}
Xin Yin
  • 2,896
  • 21
  • 20
1
def list_to_dict(l):
    d = {}
    for key, val in l:
         if key in d:
             if isinstance(d[key], list):
                 d[key].append(val)
             else:
                 d[key] = [d[key], val]
         else:
             d[key] = val
    return d

sw_fd_list2 = [['a', 1],['b', 2],['c', 3],['c', 1],['c', 9],['d', 8],['d', 4]]
res = list_to_dict(sw_fd_list2)
Quentin THEURET
  • 1,222
  • 6
  • 12
0

Pretty similar question: https://stackoverflow.com/a/960753/1317856

>>> l = [['a', 1],['b', 2]['c', 3]['c', 1]['c', 9]['d', 8]['d', 4]]
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for a, b in l:
    d[a].append(b)
>>> dict(d)
{'a': [1], 'c': [3, 1, 9], 'b': [2], 'd': [8, 4]}
Community
  • 1
  • 1
denself
  • 106
  • 1
  • 2