0
from collections import OrderedDict

l = [('Monkey', 71), ('Monkey', 78), ('Ostrich', 80), ('Ostrich', 96), ('Ant', 98)]

d = OrderedDict()
for i, j in l:
    d[i] = j
print d
OrderedDict([('Monkey', 78), ('Ostrich', 96), ('Ant', 98)])

The expected 'd' should be:

OrderedDict([('Monkey', (71,78)), ('Ostrich', (80,96)), ('Ant', 98)])

No problem if all values are tupled or listed.

Roman
  • 3,007
  • 8
  • 26
  • 54
  • 3
    Why was that the expected output? You can only have one value per key, and at the moment you're *replacing* the previous one. – jonrsharpe Mar 28 '16 at 14:07
  • yes the expected output should include all corresponding values, but did not know how to do it. – Roman Mar 28 '16 at 14:09
  • 3
    You need to review your code carefully and understand what the `d[i] = j` is actually doing in your code. Look at the data structure you are expecting. Look at what you are doing. Determine how to properly create that data structure within the context of updating values in a dictionary. Use the docs Luke. – idjaw Mar 28 '16 at 14:09
  • @idjaw I tried as `d[i].append(j)` but `KeyError: 'Monkey'` – Roman Mar 28 '16 at 14:13
  • @jean well: 1. That won't work if that key isn't there yet; and 2. It also won't work on a tuple, which is immutable. Think harder, do some more experiments. – jonrsharpe Mar 28 '16 at 14:14
  • @jonrsharpe no more idea, could you help me? – Roman Mar 28 '16 at 14:17
  • @jean no, this isn't a tutorial service and there are plenty of questions about dictionaries with container values on SO already. For example: http://stackoverflow.com/q/6190331/3001761 – jonrsharpe Mar 28 '16 at 14:18

3 Answers3

5

Instead of replacing the value each time, add it to the tuple:

>>> l = [('Monkey', 71), ('Monkey', 78), ('Ostrich', 80), ('Ostrich', 96), ('Ant', 98)]
>>> d = OrderedDict()
>>> for i, j in l:
...     if i in d:
...         d[i] += (j,)
...     else:
...         d[i] = (j,)
... 
>>> d
OrderedDict([('Monkey', (71, 78)), ('Ostrich', (80, 96)), ('Ant', (98,))])

BTW, since tuples are immutable, every append creates a new object. This would be more efficient if you use lists.

Eugene Yarmash
  • 142,882
  • 41
  • 325
  • 378
  • 1
    @jean: `for i, j in l: d.setdefault(i, []).append(j)` – GingerPlusPlus Mar 28 '16 at 14:24
  • @GingerPlusPlus That's fine; could you explain for me how your code works? – Roman Mar 28 '16 at 14:28
  • 1
    @jean: sure. If `i in d`, `d.setdefault(i, [])` returns `d[i]`, otherwise it performs `d[i] = []` and returns that `[]`. Then, `.append(j)` appends `j` to the end of the list. There are many other ways to achieve the same effect, including `if i in d ... else`, `try ... except KeyError`, and `d = collections.defaultdict(list)` – GingerPlusPlus Mar 28 '16 at 14:41
1

Here's an approach using groupby:

from itertools import groupby

l = [('Monkey', 71), ('Monkey', 78), ('Ostrich', 80), ('Ostrich', 96), ('Ant', 98)]
                # Key is the animal, value is a list of the available integers obtained by
d = OrderedDict((animal, [i for _, i in vals])
                for (animal, vals) in
                # Grouping your list by the first value inside animalAndInt, which is the animal
                groupby(l, lambda animalAndInt: animalAndInt[0]))
# If you want a tuple, instead of [i for _, i in vals] use tuple(i for _, i in vals)
print(d)
>>> OrderedDict([('Monkey', [71, 78]), ('Ostrich', [80, 96]), ('Ant', [98])])
Bahrom
  • 4,752
  • 32
  • 41
1
for i, j in l:
    if i in d:
        #d[i] = (lambda x: x if type(x) is tuple else (x,))(d[i])
        #Eugene's version:
        if not isinstance(d[i], tuple): 
             d[i] = (d[i],)
        d[i] += (j,)
    else:
        d[i] = j

gives the following. Notice that 98 in 'Ant' is not "tupled" as asked in the original question.

OrderedDict([('Monkey', (71, 78)), ('Ostrich', (80, 96)), ('Ant', 98)])
aless80
  • 3,122
  • 3
  • 34
  • 53