16

Possible Duplicate:
Tuple value by key

How do i find the country name by having its code,

COUNTRIES = (
   ('AF', _(u'Afghanistan')),
   ('AX', _(u'\xc5land Islands')),
   ('AL', _(u'Albania')),
   ('DZ', _(u'Algeria')),
   ('AS', _(u'American Samoa')),
   ('AD', _(u'Andorra')),
   ('AO', _(u'Angola')),
   ('AI', _(u'Anguilla'))
)

I have code AS, find its name without using forloop on COUNTRIES tuple?

Community
  • 1
  • 1
Ahsan
  • 11,516
  • 12
  • 52
  • 79

3 Answers3

30

You can simply do:

countries_dict = dict(COUNTRIES)  # Conversion to a dictionary mapping
print countries_dict['AS']

This simply creates a mapping between country abbreviations and country names. Accessing the mapping is very fast: this is probably the fastest method if you do multiple lookups, as Python's dictionary lookup is very efficient.

Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260
  • Do you know if the conversion + lookup is faster than looping through the tuples for a match? – daramarak Jan 05 '12 at 10:09
  • @daramarak: for a single lookup creating a dictionary should be slower. see my downvoted answer.. :/ – Karoly Horvath Jan 05 '12 at 11:22
  • @yi_H: interesting point raised! But the time complexity for a **for loop** is O(n), and accessing a tuple/dictionary is O(1). Are you talking about the time consumed for type casting? Please specify your logic. – Zain Khan Jan 05 '12 at 11:37
  • 3
    @mangobug: creating the dictionary is O(n) and you have to allocate space and copy the entries... for that, you obviously have to loop through the tuple. now compare this with a simple loop which finds the appropriate entry. – Karoly Horvath Jan 05 '12 at 11:54
  • point taken!! +1 to your answer too :) – Zain Khan Jan 05 '12 at 12:01
4
COUNTRIES = (
   ('AF', (u'Afghanistan')),
   ('AX', (u'\xc5land Islands')),
   ('AL', (u'Albania')),
   ('DZ', (u'Algeria')),
   ('AS', (u'American Samoa')),
   ('AD', (u'Andorra')),
   ('AO', (u'Angola')),
   ('AI', (u'Anguilla'))
)

print (country for (code, country) in COUNTRIES if code=='AD').next()
#>>> Andorra

print next((country for (code, country) in COUNTRIES if code=='AD'), None)
#Andorra
print next((country for (code, country) in COUNTRIES if code=='Blah'), None)
#None

# If you want to do multiple lookups, the best is to make a dict:
d = dict(COUNTRIES)
print d['AD']
#>>> Andorra
Eric O. Lebigot
  • 91,433
  • 48
  • 218
  • 260
Rusty Rob
  • 16,489
  • 8
  • 100
  • 116
  • 2
    This is an already stated answer by many. Why repeat yourself? – Zain Khan Jan 05 '12 at 10:05
  • 1
    I have not seen example with generator in other examples, this is nice. +1 – Ski Jan 05 '12 at 10:10
  • The generator version could be made shorter by doing `next(country for code,country in COUNTRIES if code=='AD')`. The builtin `next(a) -> a.next()`. (Admittedly, in a micro-benchmark the builtin `next` will perform worse because of this, but it's a fun fact, anyway.) There is actually one way in which using the builtin `next` is better: its `default` argument. e.g. `next((country for code,country in COUNTRIES if code=='AD'), None)` will return `None` if there is no language match. – Chris Morgan Jan 05 '12 at 11:32
  • +1 for the efficient generator. Note that `next(…)` is officially recommended over your `….next()`, though, if I remember correctly. – Eric O. Lebigot Jan 05 '12 at 13:24
1

You can't.

Either

[x[1] for x in COUNTRIES if x[0] == 'AS'][0]

or

filter(lambda x: x[0] == 'AS', COUNTRIES)[0][1]

but these are still "loops".

Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176
  • No downvote, but both these solutions are inefficient: all the countries are re-read for each lookup, even if the 'AS' country is found at the beginning of the list of countries. – Eric O. Lebigot Jan 05 '12 at 10:00
  • You mean it's inefficient *if* there are multiple lookups. – Karoly Horvath Jan 05 '12 at 10:05
  • These methods are actually *always* inefficient: even if the 'AS' country is found right at the beginning of the COUNTRIES list, the rest of the list is unnecessarily read anyway. robert king's answer shows an efficient way to do something similar. – Eric O. Lebigot Jan 05 '12 at 13:22
  • 1
    @EOL: yepp, `(..).next()` would be better.. – Karoly Horvath Jan 05 '12 at 13:29