开发者

Python: How to custom order a list?

Obs: I know lists in python are not order-fixed, but think that this one will be. And I'm using Python 2.4

I have a list, like (for example) this one:

mylist = [ ( u'Article', {"...some_data..."}    ) ,
           ( u'Report' , {"...some_data..."}    ) ,
           ( u'Book'   , {"...another_data..."} ) ,
...#continue
]

This variable mylist is obtained from a function, and the 'order' of the list returned will vary. So, sometimes it will be like on the example. Sometimes, the 'Report' will come before 'Article', etc.

I have a fixed order that I want on this list (and isn't the alphabetical).

Let's say that my fixed order is: 'Report', 'Article', 'Book', ...

So, what I want is that: whatever order 'mylist' is instantiated, I want to reorder it making 'Report' stay on front, 'Article' on second, etc...

What's the best approach to reorder my list (taking the first element of the tuple of each item on list) using my 'custom' order?

Answer:

I ended up with this:

mylist became a list o开发者_如何学Cf dicts, like this:

mylist = [{'id':'Article', "...some_data..."} ,
        ...etc
]

each dict having a 'id' that had to be sorted.

Saving the correct order on a listAssigning the correct_order on a list:

correct_order = ['Report', 'Article', 'Book', ...]

and doing:

results = sorted([item for item in results], cmp=lambda x,y:cmp(correct_order.index(x['id']), correct_order.index(y['id'])))


You could use a dictionary that would map every first element to its "weight" and then check this dictionary inside a sorting function.

Something like:

d = { "Report": 1,
      "Article": 2,
       "Book": 3 }
result = sorted(mylist, key=lambda x:d[x[0]])


You could use a dictionary, that would allow you to access "Book", "Article", etc. without having to care about the order. I would put the data from that list into a dict that look like this:

mydict = { u'Article': "somedata",
           u'Report': "someotherdata", ...}

If you really want to sort your list in the way you described, you can use the list.sort with a key function that represents your particular sort order (Documentation). You need the key function as you need to access only the first element and your sorting order also is not alphabetical.


This way creates a dict and pulls the items from it in order

mylist = [ ( u'Article', {"...some_data..."}    ) ,
           ( u'Report' , {"...some_data..."}    ) ,
           ( u'Book'   , {"...another_data..."} ) ,
]

mydict = dict(mylist)
ordering = [u'Report', u'Article', u'Book']

print [(k,mydict[k]) for k in ordering]

This way uses sort with O(1) lookups for the ordering

mylist = [ ( u'Article', {"...some_data..."}    ) ,
           ( u'Report' , {"...some_data..."}    ) ,
           ( u'Book'   , {"...another_data..."} ) ,
]

mydict = dict(mylist)
ordering = dict((k,v) for v,k in enumerate([u'Report', u'Article', u'Book']))

print sorted(mydict.items(), key=lambda (k,v): ordering[k])


More generally, there could be elements of the mylist that are not in the specified fixed order. This will order according to the rule, but leave alone the relative order of everything outside of the rule:

def orderListByRule(alist,orderRule,listKeys=None,dropIfKey=None):
    ###
    #######################################################################################
    """ Reorder alist according to the order specified in orderRule. The orderRule lists the order to be imposed on a set of keys. The keys are alist, if listkeys==None, or listkeys otherwise.  That is, the length of listkeys must be the same as of alist. That is, listkeys are the tags on alist which determine the ordering.  orderRule is a list of those same keys and maybe more which specifies the desired ordering.
    There is an optional dropIfKey which lists keys of items that should be dropped outright.
    """
    maxOR = len(orderRule)
    orDict = dict(zip(orderRule, range(maxOR)))
    alDict = dict(zip(range(maxOR, maxOR+len(alist)),
                      zip(alist if listKeys is None else listKeys, alist)))
    outpairs = sorted(  [[orDict.get(b[0],a),(b)] for a,b in alDict.items()]  )
    if dropIfKey is None: dropIfKey=[]
    outL = [b[1] for a,b in outpairs if b[0] not in dropIfKey]
    return outL

def test_orderListByRule():
    L1 = [1,2,3,3,5]
    L2 = [3,4,5,10]
    assert orderListByRule(L1, L2) == [3, 3, 5, 1, 2]
    assert orderListByRule(L1, L2, dropIfKey=[2,3]) == [5, 1,]
    Lv = [c for c in 'abcce']
    assert orderListByRule(Lv, L2, listKeys=L1) == ['c', 'c', 'e', 'a', 'b']
    assert orderListByRule(Lv, L2, listKeys=L1, dropIfKey=[2,3]) == ['e','a']


This function sorts through a custom list, but if any element is not in the list, an error will not be generated. However, this element will be at the end of the line.

def sort_custom(ordem_custom : list , origin : list) -> list:
    
    list_order_equals = [c for c in ordem_custom if (c in origin)]
    list_no_equals = [c for c in origin if (not c in ordem_custom)]
    list_order = list_order_equals + list_no_equals
    
    return list_order

#Exemple

custom_order = ('fa','a','b','c','d','e')
my_list =  ('e','c','fa','h','h','g')

result = sort_custom(custom_order,my_list)
print(result)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜