1

I'm trying to make a dictionary that returns the same value for diferent keys, currently I have it like so:

GScale = {
    ('S1') : 'gN',
    ('S2') : 'aN',
    ('S3') : 'bN',
    ('N1','G1','A2','B2') : 'gG',
    ('N2','G2','A1','B3','C2') : 'aA',
    ('N3','G3','A3','B1','C3','D2') : 'bB',
    ('N4','A4','B4','C1','D3','E2') : 'cC',
    ('N5','B5','C4','D1','E3','F2') : 'dD',
    ('N6','C5','D4','E1','F3') : 'eE',
    ('N7','D5','E4','F1') : 'fF'
}

When I ask for GScale['S1'] I succesfully get 'gN' but when I ask for GScale['N1'] I get a key error, what could be the problem?

IvanHid
  • 669
  • 7
  • 25
  • 5
    because `N1` isn't a key, it's a part of a tuple which is a key. try `GScale[('N1','G1','A2','B2')]` S1 key isn't a tuple. – Jean-François Fabre Nov 12 '17 at 20:58
  • 1
    There are exactly 10 keys in the dict. `N1` isn't one of them. – Tom Karzes Nov 12 '17 at 21:01
  • I need to get gG when asking for any of these keys ('N1','G1','A2','B2'), not all of them as a tuple, is there any way to do that or should I just make individual tuples for every key? – IvanHid Nov 12 '17 at 21:02
  • 1
    There's no need to make them tuples. Just use the individual strings directly. And note that `('S1')` isn't a tuple, it's just `'S1'`. To make a singleton tuple, you must append a trailing comma to distinguish it from a parenthesized expression, e.g., `('S1',)`. – Tom Karzes Nov 12 '17 at 21:05
  • @TomKarzes that makes a lot of copy/paste. The way OP wrote means that there are a lot of keys leading to the same value. – Jean-François Fabre Nov 12 '17 at 21:06
  • @Jean-FrançoisFabre In that case, why not process the existing dict to create a new one with the desired keys. Fast and simple. – Tom Karzes Nov 12 '17 at 21:07
  • @TomKarzes exactly what my answer does :) – Jean-François Fabre Nov 12 '17 at 21:08

2 Answers2

2

your dictionary has 2 types of keys:

  • strings like ("S1") (parenthesis don't make a tuple here, probably the cause of your confusion)
  • tuples like ("N1",...)

so querying the dict with just N1 doesn't work because N1 isn't a key, it's a part of some key tuple.

If you want to write it like this for convenience, I'd suggest that you rework it afterwards in a dictionary comprehension:

GScale = {
    ('S1',) : 'gN',   # trailing comma is needed now
    ('S2',) : 'aN',
    ('S3',) : 'bN',
    ('N1','G1','A2','B2') : 'gG',
    ('N2','G2','A1','B3','C2') : 'aA',
    ('N3','G3','A3','B1','C3','D2') : 'bB',
    ('N4','A4','B4','C1','D3','E2') : 'cC',
    ('N5','B5','C4','D1','E3','F2') : 'dD',
    ('N6','C5','D4','E1','F3') : 'eE',
    ('N7','D5','E4','F1') : 'fF'
}

GScale = {k:v for kl,v in GScale.items() for k in kl}

Now GScale is:

{'N1': 'gG', 'B5': 'dD', 'D4': 'eE', 'C3': 'bB', 'A3': 'bB', 'S3': 'bN', 'F3': 'eE', 'C4': 'dD', 'E3': 'dD', 'D1': 'dD', 'A4': 'cC', 'E2': 'cC', 'G2': 'aA', 'C5': 'eE', 'A2': 'gG', 'N2': 'aA', 'E4': 'fF', 'E1': 'eE', 'D5': 'fF', 'N6': 'eE', 'N7': 'fF', 'B1': 'bB', 'A1': 'aA', 'C1': 'cC', 'F2': 'dD', 'B3': 'aA', 'G3': 'bB', 'F1': 'fF', 'D3': 'cC', 'B2': 'gG', 'B4': 'cC', 'G1': 'gG', 'S1': 'gN', 'C2': 'aA', 'N5': 'dD', 'S2': 'aN', 'N3': 'bB', 'D2': 'bB', 'N4': 'cC'}

now the key/value pairs are expanded and querying any N1 or letter+digit works.

(Note that single value keys have a comma added to make them tuples of 1 element so the iteration on the key tuples in the dictionary comprehension work, not adding the comma will make it appear to work, but it will create keys with individual letters of S1, S2 ...: not what you want)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • Thanks for the reply, is there any way to write it similar to how I did it? I'm new to Python and what I want to do is get the same answer ('gG') when asking for GScale['N1'], GScale['G1'], GScale['A2'], GScale['B2'] and so on for every tuple. – IvanHid Nov 12 '17 at 21:06
  • that's exactly what my answer does. Just add commas after the "S" keys to make them 1-element tuples and you can transform your non-working dict into a working one. Try it, it works as you wish. – Jean-François Fabre Nov 12 '17 at 21:07
  • that's because you didn't add the comma, so the keys are S, 1, 2, 3... (iterating on strings) – Jean-François Fabre Nov 12 '17 at 21:09
  • Thank you so much for your explanation! You are a life saver :) – IvanHid Nov 12 '17 at 21:09
  • I have added the comma and it now works just fine :) – IvanHid Nov 12 '17 at 21:10
1

As explained in the comments, your code doesn't have a chance to work - as in the dictionaries there are always single keys, not multiple ones. In your example the single keys are tuples of values, still they constitute a single key in each pair.

What you are after seems to be the goal of multi_key_dict as found at https://pypi.python.org/pypi/multi_key_dict

I haven't tried it, but if you used the library, you could go with:

from multi_key_dict import multi_key_dict

gscale = multi_key_dict()
# ... other
gscale['N1','G1','A2','B2'] = 'gG'
gscale['N2','G2','A1','B3','C2'] ='aA'
# ... other

# then...
print(gscale['N1']) # yields 'gG'
Grzegorz Oledzki
  • 23,614
  • 16
  • 68
  • 106