Python: sorting a list by two attributes

I have a list like this:

class Ind(object): def __init__(self,ID,mate): self.ID=ID self.mate=mate population=[Ind(8,None), Ind(1,2), Ind(20,3), Ind(2,1), Ind(12,None), Ind(3,20), Ind(10,11), Ind(11,10)] 

You can imagine this population list as a collection of individuals who all have ID . Some of them have mate (a person who is present in the same population or on the same list). The mate value is actually an assistant ID ! Therefore, if there is an Ind instance, the ID attributes are 12, and the mate is 34, then there will be an individual in the list, the ID 34, and the mate is 12. Persons who do not have mate have None in the mate attribute. Does it make sense?

I would like to sort this list to the first individual assistants with the last, the second individual assistant with the second to the last person, etc. Personality, the mate attribute is equal to None should be in the middle of the list.

There are many possible solutions that match what I want. Here is one example of these outputs for the above list:

 population=[Ind(1,2), Ind(20,3), Ind(10,11), Ind(8,None), Ind(12,None), Ind(11,10), Ind(3,20), Ind(2,1)] 
+4
source share
4 answers

You can try something like this:

 def custom_sort(population): pop_dict = { ind.ID: ind for ind in population } start = [] nones = [] end = [] for ind in population: if ind.mate is None: nones.append(ind) elif pop_dict[ind.mate] not in start: start.insert(0, ind) end.append(pop_dict[ind.mate]) return start + nones + end 

Under the assumption that “being an assistant” is a 1 to 1 ratio.

+5
source

You just need a key for the sort function. The following example requires people to be monogamous and not to marry themselves. It also requires that if (a, b) is indicated, (b, a) is also listed. If these prerequisites are not satisfied, and Ind (2,1) can occur without Ind (1,2), this function will put Ind (2,1) at the end of the list. The first index in the key function is the type: "first" in relationship (where IDmate) is in third place. These first and second types are sorted in order by their identifiers; the latter type is sorted in reverse order by its helper.

 def keyfun(x): if x.mate==None: return (1,x.ID) elif x.ID<x.mate: return (0,x.ID) else: return (2,-x.mate) sorted(population,key=keyfun) 

Another way to handle this, still assuming that if (a, b) is on the list (b, a) is also on the list, you just need to perform the preliminary process, removing the (b, a) cases, and then execute the postprocess adding them back in reverse order.

+2
source

How about this one. Divide the list into three lists, one with ID < mate , one with ID > mate , and one with mate is None . Then merge the sorted lists, sorted by ID.

I added the __repr__ method for the Ind class for readability of the output.

 class Ind(object): def __init__(self,ID,mate): self.ID=ID self.mate=mate def __repr__(self): return 'Ind({},{})'.format(self.ID,self.mate) population=[Ind(8,None), Ind(1,2), Ind(2,3), Ind(2,1), Ind(12,None), Ind(3,2), Ind(10,11), Ind(11,10)] def custom_sort(pop): singles, less, more = [], [], [] for p in pop: if p.mate is None: singles.append(p) elif p.ID < p.mate: less.append(p) elif p.ID > p.mate: more.append(p) comp = lambda x,y: cmp(x.ID,y.ID) return sorted(less,cmp=comp) + sorted(singles,cmp=comp) + sorted(more,cmp=comp,reverse=True) print custom_sort(population) 

It is output:

 [Ind(1,2), Ind(2,3), Ind(10,11), Ind(8,None), Ind(12,None), Ind(11,10), Ind(3,2), Ind(2,1)] 
0
source

There are many features that you can use with key costum features:

 def my_key(ind): if ind.mate is None: return 0 if ind.ID < ind.mate: return -ind.ID - 1 else: return ind.mate + 1 population.sort(key=my_key) 

This suggests that identifiers will never be negative. If the identifiers are always greater than 0, you can refuse - 1 and + 1 .

0
source

Source: https://habr.com/ru/post/1498979/


All Articles