4

is there any way to store duplicate keys in a dictionary?

I have a specific requirement to form pairs of requests and responses.

Requests from a particular node to another particular node form same keys. I need to store both those.

But if I tried to add them to dictionary, first one is being replaced by second. Is there any way?

user207421
  • 305,947
  • 44
  • 307
  • 483
newbie555
  • 467
  • 3
  • 6
  • 12
  • 9
    Wouldn't a *dictionary* by definition *not* allow duplicate keys? – Levon Jun 21 '12 at 15:21
  • As soon as I see the word "node" - I think 'graph'. Could you comment further on your end goal rather than the implementation issues you feel you *may* have – Jon Clements Jun 21 '12 at 15:32

8 Answers8

10

While I'm not 100% sure, I'm pretty sure the answer is no. That sort of violates the purpose of a dictionary in python. How about you change the value to lists so instead of

{Key:value}

you have

{Key:[Value1,value2]}
8bitwide
  • 2,071
  • 1
  • 17
  • 24
10

I can think of two simple options, assuming you want to keep using a dictionary.

  1. You could map keys to lists of items. A defaultdict from the collections module makes this easy.

    >>> import collections
    >>> data = collections.defaultdict(list)
    >>> for k, v in (('a', 'b'), ('a', 'c'), ('b', 'c')):
    ...     data[k].append(v)
    ... 
    >>> data
    defaultdict(<type 'list'>, {'a': ['b', 'c'], 'b': ['c']})
    
  2. You could use additional data to disambiguate the keys. This could be a timestamp, a unique id number, or something else. This has the advantage of preserving a one-to-one relationship between keys and values, and the disadvantage of making lookup more complex, since you always have to specify an id. The example below shows how this might work; whether it's good for you depends on the problem domain:

    >>> for k, v in (('a', 'b'), ('a', 'c'), ('b', 'c')):
    ...     i = 0
    ...     while (k, i) in data:
    ...         i += 1
    ...     data[(k, i)] = v
    ... 
    >>> data
    {('a', 1): 'c', ('b', 0): 'c', ('a', 0): 'b'}
    
senderle
  • 145,869
  • 36
  • 209
  • 233
7

An alternative to the defaultdict might be

d = {}
d.setdefault(newkey, []).append(newvalue)

This does the same: append newvalue to a list which is either already in the dictionary at the given newkey, or if not, will be put there.

glglgl
  • 89,107
  • 13
  • 149
  • 217
4

There is no way to do this, no. Dictionaries rely on the keys being unique - otherwise, when you request or set a key, what value would be returned or overwritten?

What you could do, however, is store a list as the value for the dictionary, and then add your values to that list, rather than replacing the existing value.

You might want to use a collections.defaultdict to do this, to avoid making the lists by hand each time a new key is introduced.

Gareth Latty
  • 86,389
  • 17
  • 178
  • 183
  • What will be the keys to that dictionary? – newbie555 Jun 21 '12 at 15:25
  • ok i get it...i can use count as the key to the dictionary and for each list i add as the value, for the next entry, i can increase the count. – newbie555 Jun 21 '12 at 15:29
  • @rockluke What you are describing there is a list, not a dictionary. If your keys are indicies, then a list is more suitable. – Gareth Latty Jun 21 '12 at 15:30
  • 1
    @Feiteira You are describing a different situation—those keys are, by definition, not duplicates (they don't equal each other). It makes the dictionary essentially useless though as you have to have that exact key object to access the value. At that point, why not just put the value in the key object and forego the dictionary entirely? You could of course access them by iteration, but then why not just use a list of tuples? – Gareth Latty Jul 09 '19 at 20:30
4

Use lists to store all values for the equal keys:

{a:b, a:c}  # foolish, won't work
{a: [ b, c ]}  # works like a charm!

You also might want to use

from collections import defaultdict
d = defaultdict(list)
d[a].append(b)

to fill your dictionary in an easy way.

Alfe
  • 56,346
  • 20
  • 107
  • 159
  • ok i get it...i can use count as the key to the dictionary and for each list i add as the value, for the next entry, i can increase the count. – newbie555 Jun 21 '12 at 15:28
1

I like the answers using collections.defaultdict. That's the way I would probably go.

But that assumes a dict or dict-like structure and a one-to-many mapping is the right solution. Rereading the question, the requirement to "form pairs of requests and responses" might lead to a simpler list-of-tuples (or list-of-lists) approach. E.g.:

pairs = []
pairs.append( (request, response) )

Which might create a list like:

[ ('GET /', 200), ('GET /index.html', 200), ('GET /x', 403), ('GET /', 200), ]

It's only lightly structured, but depending on what you want to do with it, could be fine.

Jonathan Eunice
  • 21,653
  • 6
  • 75
  • 77
1

A more elegant solution:

def add_to_dict(towhat, key, value):
    info = towhat.get(key, [])
    info.append(value)
    towhat[key] = info

alternate = {}

add_to_dict(alternate,"Andrew","Cambridge")
add_to_dict(alternate,"Barbara","Bloomsbury")
add_to_dict(alternate,"Andrew","Corsica")

print alternate
0

A dictionary, by definition, requires that keys be unique identifiers. You can either:

  1. Use a different data structure such as a list or tuple that allows for duplicate entries.
  2. Use a unique identifier for your dictionary keys, much the same way that a database might use an auto-incrementing field for its key id.

If you are storing a lot of request/response pairs, you might be better off with a database anyway. It's certainly something to consider.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199