0

I am with no math background so struggling in a simple thing.

from dataclasses import dataclass

@dataclass
class Country:
    cc:str
    name:str


countries_info = [
    ('DE', 'Germany'),
    ('EP', 'Europe'),
    ('US', 'United States'),
    ('IN', 'India')
]
countries = [Country(cc, name)
                for cc, name in countries_info]

# sort based on a particular order
order = ['US', 'IN']
sorted(countries, key=lambda x: order.index(x.cc) if x.cc in order else -1)

Out put:

[Country(cc='DE', name='Germany'),
 Country(cc='EP', name='Europe'),
 Country(cc='US', name='United States'),
 Country(cc='IN', name='India')]

What I want is

[Country(cc='US', name='United States'),
 Country(cc='IN', name='India'),
 Country(cc='DE', name='Germany'),
 Country(cc='EP', name='Europe')]

Means only sort the countries based on order and make them appear first. do not touch the order of rest

In case of conflict like the same cc, this is desirable.

[Country(cc='US', name='United States'),
 Country(cc='US', name='United States of America')
 Country(cc='IN', name='Bharat'),
 Country(cc='IN', name='India'),
 Country(cc='DE', name='Germany'),
 Country(cc='EP', name='Europe')]

Means It doesn't matter which comes first in case of conflict.

Rahul
  • 10,830
  • 4
  • 53
  • 88

1 Answers1

3

The return of the key function is used to sort the list. By returning -1 for those not in order, you inadvertently pushed them to the front instead. The following code should work:

sorted(countries, key=lambda x: order.index(x.cc) if x.cc in order else len(order))

I returned len(order) for others, because index will always be less than it. sorted ensures a stable sort, meaning for equal values the original order is not changed.

Edit: This would also apply to duplicated cc values inside order, because index would return the first occurrence for each of them. So their relative order would also remain unchanged. If you want a specific order, you can simply replace order.index(x.cc) with another suitable value.

shriakhilc
  • 2,922
  • 2
  • 12
  • 17
  • One more question. so if order is large (but not more than 150), it will call len(order) for every time? will it be advisable to create something like inf = len(order) and use inf? I think yes. – Rahul May 31 '19 at 10:49
  • Python `len` is [constant time](https://stackoverflow.com/questions/1115313/cost-of-len-function), so I don't think it will matter. But yes, that would work too. – shriakhilc May 31 '19 at 10:51
  • 1
    Thanks. Why use extra line unnecessary. – Rahul May 31 '19 at 10:57