1

I want iterating on dict key as explained in the SilentGosht answer. But on some strings i get error. My environment is QGIS 2.14 python terminal

Here is my dict:

dictAliases = {
('ID_WS_INT','ID_WS'): 'B1',
('PGM_START','PGM_START_DATE','PGM_START_'): 'Debut programme'
}

Here my code to iterate on dict:

next(v for k, v in dictAliases.items() if 'PGM_START_' in k)

It works fine

BUT if put the dict in a separate file and import it as:

import sys

sys.path.append('C:\workspace\script')
import osirisdict
next(v for k, v in osirisdict.dictAliases.items() if 'ID_WS_int'in k)

I get:

Traceback (most recent call last): File "", line 1, in StopIteration

It's only on some strings as ID_WS_int in place of ID_WS_INT or PGM_START_ in place of PGM_START_DATE

I can't understand why the import changes things

here is the imported dict:

dictAliases = {
('ID_WS_INT','ID_WS'): 'B1',
('PGM_START','PGM_START_DATE','PGM_START_'): 'Debut programme',
('IMP_TYPE_F','IMP_TYPE_FR'): 'Type impetrant',
('PGM_START','PGM_START_DATE','PGM_START_'): 'Debut programme',
}
Community
  • 1
  • 1
jlSta
  • 294
  • 3
  • 12

1 Answers1

1

The import has nothing to do with that.

in in the list checks for exact string match.

The first example works PGM_START_ because you're respecting the case.

In the second case, since your string only matches if we disregard case, in fails to find the item in the tuple, the generator is empty, and you're getting the StopIteration error.

Quickfix for that one:

next(v for k, v in osirisdict.dictAliases.items() if 'ID_WS_INT' in k)

If you don't know about the case, you could fix it the way below using any and comparing uppercase versions of the items in the keys:

next(v for k, v in dictAliases.items() if any('ID_WS_INT'==i.upper() for i in k))

But it's still a very non-performant way to perform lookups, you're not using the dictionary lookup speed at all.

I suggest that you build a new dictionary, with 1 key (uppercased) by tuple item:

newdict = {k.upper():v for t,v in dictAliases.items() for k in t}

which gives for newdict:

{'PGM_START_DATE': 'Debut programme', 'ID_WS_INT': 'B1', 'PGM_START_': 'Debut programme', 'PGM_START': 'Debut programme', 'ID_WS': 'B1'}

Then you can access the elements using get:

newdict.get('ID_WS_INT')

(which returns None if not found). That'll be more efficient and more pythonic.

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • OK, Thank you. The creation of a new dict works perfectly but sorry i cannot add +1, no points enough – jlSta Mar 09 '17 at 07:54
  • The 'newdict = {k.upper():v for t,v in dictAliases.items() for k in t} ' generates wrong key values. It takes the first letter of the real key in place of the key itself. But i let the point because i think this is not totally wrong. – jlSta Mar 10 '17 at 19:01
  • this formula applied to your data gives `{'PGM_START_DATE': 'Debut programme', 'ID_WS_INT': 'B1', 'PGM_START_': 'Debut programme', 'PGM_START': 'Debut programme', 'ID_WS': 'B1'}` so it's correct. I have tested it. Did you change your input data? – Jean-François Fabre Mar 10 '17 at 20:08
  • No, but it was just an extract because i have more than 50 lines. But i created a new dict with a line by key for the same value and it works. – jlSta Mar 10 '17 at 20:53
  • good. Next time you have an issue with an answer, it's okay to unaccept, but it's better to ping the poster so he/she can fix that. Some posters would barely have noticed the unacceptance and you wouldn't have had your solution. Whatever. Cheers for that. – Jean-François Fabre Mar 10 '17 at 20:55