Python:根据两个属性对列表进行排序

时间:2013-08-26 15:15:36

标签: python sorting

我有以下类型的列表:

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)]

您可以将此列表population视为所有拥有ID的个人群体。他们中的一些人有一个mate(一个人出现在同一人口或相同的名单中)。 mate值实际上是配偶的ID!因此,如果Ind的实例ID等于12且mate等于34,那么列表中必须有一个ID等于34且其mate等于12.没有mate的个人None属性中有mate。它有意义吗?

我想对这个列表进行排序,以便第一个人与最后一个人交配,第二个人与倒数第二个人交配,等等......属性mate的个人等于{ {1}}应该位于列表的中间位置。

有许多可能的输出符合我的要求。以下是上述列表中这些输出的一个示例:

None

4 个答案:

答案 0 :(得分:5)

您可以尝试这样的事情:

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

这是假设“作为配偶”是一对一的关系。

答案 1 :(得分:2)

您只需要一个用于排序功能的键。以下示例要求个人是一夫一妻制而不是与自己结婚。它还要求列出if(a,b),(b,a)也列出。如果不满足这些先决条件并且Ind(2,1)可以在没有Ind(1,2)的情况下发生,则此函数将Ind(2,1)放在列表​​的末尾。关键函数中的第一个索引是类型:关系中的“first”(IDmate)排在第三位。这些第一和第二类型按其ID排序;最后一种类型由其配偶以相反的顺序排序。

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)

另一种处理这个的方法,仍然假设if(a,b)在列表中(b,a)也将在列表中,只是通过删除(b,a)个案进行预处理,然后进行后处理将它们以相反的顺序重新添加。

答案 2 :(得分:0)

这个怎么样?将列表拆分为三个列表,一个列表为ID < mate,第二个列表为ID > mate,第三个列表为mate is None。然后,连接已排序的列表,每个列表通过ID进行排序。

我在__repr__类中添加了Ind方法,以提高输出可读性。

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)

输出:

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

答案 3 :(得分:0)

使用自定义键功能可以做很多事情:

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)

这假设ID永远不会是负数。如果ID始终大于0,您可以放弃- 1+ 1