adyavanapalli
adyavanapalli

Reputation: 500

I need a way to map multiple keys to the same value in a dictionary

Admittedly, this question seems like it might be a popular one, but I couldn't really find it (perhaps I wasn't using the right search terms). Anyway, I need something of this sort:

tel = {}
tel['1 12'] = 1729
tel['9 10'] = 1729
tel['1 2'] = 9
tel['2 1'] = 9
tel['1 1'] = 2
print(tel)

{['1 1'] : 2, ['1 2', '2 1'] : 9, ['1 12', '9 10'] : 1729}

So whenever a key's value is already in the dict, append the key to the list of keys mapping to that value; else, add the key value pair to the dict.

EDIT I'm sorry if I confused the lot of you, and I'm REALLY sorry if the following confuses you even more :)

This is the original problem I wanted to solve: Given the equation a^3 + b^3, produce a dictionary mapping all positive integer pair values for a, b less than 1000 to the value of the equation when evaluated. When two pairs evaluate to the same value, I want the two pairs to share the same value in the dictionary and be grouped together somehow. (I'm already aware that I can map different keys to the same value in a dict, but I need this grouping).

So a sample of my pseudocode would be given by:

for a in range(1, 1000):
    for b in range(1, 1000):
        map pair (a, b) to a^3 + b^3

For some integer pairs (a, b) and (p, q) where a != p, and b != q, a^3 + b^3 == p^3 + q^3. I want these pairs to be grouped together in some way. So for example, [(1, 12), (9, 10)] maps to 1729. I hope this makes it more clear what I want.

EDIT2 As many of you have pointed out, I shall switch the key value pairs if it means a faster lookup time. That would mean though that the values in the key:value pair need to be tuples.

Upvotes: 2

Views: 9190

Answers (3)

cholm
cholm

Reputation: 481

For those coming here via search:

First, invert the mapping

>>> tmp = {1729: ['1 12','9 10'], 9: ['1 2','2 1'], 2: ['1 1']}

Then create the inverse mapping to get what you want

>>> tel = {v: k for k,vs in tmp.items() for v in vs}
>>> print(tel)
... {'1 12': 1729, '9 10': 1729, '1 2': 9, '2 1': 9, '1 1': 2}

Upvotes: 2

Nick Saccente
Nick Saccente

Reputation: 170

I know this thread is old, but I just came across this problem and here's how I solved it:

class PolyMap:
    def __init__(self):
        self._map = {}

    def __setitem__(self, key, value):
        self._map[key] = value

    def __getitem__(self, item):
        for keys in self._map:
            if item == keys:
                return self._map[item]
            if item in keys:
                return self._map[keys]
        return None


pm = PolyMap()
pm[("x", "y")] = "z"

print(pm["x"])
# >> z

print(pm["y"])
# >> z

print(pm[("x", "y")])
# >> z

print(pm["z"])
# >> None

This doesn't keep track of key components you've used, so if you use the same key component more than once, and expect consistent functionality of getitem, you'll need to pass it the tuple you created it with.

The good news is, if you know that the components of your key-tuples are all unique, then you can use this without fuss.

Upvotes: 2

ospahiu
ospahiu

Reputation: 3525

As many of the comments have already pointed out, you seem to have your key/value structure inverted. I would recommend factoring out your int values as keys instead. This way you achieve efficient dictionary look ups using the int value as a key, and implement more elegant simple design in your data - using a dictionary as intended.

Ex: {9: ('1 2', '2 1'), 2: ('1 1',), 1729: ('9 10', '1 12')}

That being said the snippet below will do what you require. It first maps the data as shown above, then inverts the key/values essentially.

tel = {}
tel['1 12'] = 1729
tel['9 10'] = 1729
tel['1 2'] = 9
tel['2 1'] = 9
tel['1 1'] = 2
#-----------------------------------------------------------
from collections import defaultdict

new_tel = defaultdict(list)
for key, value in tel.items():
    new_tel[value].append(key)

# new_tel -> {9: ['1 2', '2 1'], 2: ['1 1'], 1729: ['9 10', '1 12']}
print {tuple(key):value for value, key in new_tel.items()}
>>> {('1 2', '2 1'): 9, ('1 1',): 2, ('9 10', '1 12'): 1729}

Upvotes: 2

Related Questions