简体   繁体   中英

Custom sort on a dictionary in Python?

I want to have a custom sort on a dictionary that I generate in a nested loop. I know that five records will always be there, but there could be others based on the data I go through. I essentially want those five records in a specific order, and then the order does not matter for all records after those five.

For example, I want this:

{"Entries": [], "Groups": [], "Admin": [], "Network": [], "XYZ": [], "Subnets": []}

to be sorted to this:

{"Admin": [], "Groups": [], "Network": [], "Subnets": [], "Entries": [], "XYZ": []}

Therefore, Admin, Groups, Network, Subnets, and Entries are the five that I want in that specific order at the beginning of the dictionary, and after that the remaining entries' order does not matter. How can I do this?

You need collections.OrderedDict for that...

So, based on that, the solution is something like:

def custom_order(dct, spec):
    """
    dct - the dictionary
    spec - a list of dedicated keys
    """
    res = collections.OrderedDict()
    dct = dict(dct)
    for key in spec:
        if key in dct:
            res[key] = dct.pop(key)
    res.update(dct.items())
    return res

You first need to

  • create a list of (key, value) pairs by getting the list of items
  • Custom Sort the generated list
  • Create an OrderedDict based on the sorted result

Here is an example where I sort your data based on the length of the key

>>> from collections import OrderedDict
>>> some_dict = {"Entries": [], "Groups": [], "Admin": [], "Network": [], "XYZ": [], "Subnets": []}
>>> some_dict = OrderedDict(sorted(some_dict.items(),key = lambda e:len(e[0])))
>>> some_dict
OrderedDict([('XYZ', []), ('Admin', []), ('Groups', []), ('Subnets', []), ('Network', []), ('Entries', [])])

将数据存储为成对列表。

I've re-thought out how I approach the entire situation, and found a method that works for me.

With a dataset like the following:

{"Entries": [], "Groups": [], "Admin": [], "Network": [], "XYZ": [], "Subnets": []}

I just do the following, which works fine for me:

for menu in ["Admin", "Groups", "Network", "Subnets", "Entries"]:
    try:
        doWork(my_dataset[menu])
        del my_dataset[menu]
    except KeyError:
        # The user might not have any entries for that menu, so don't worry about it
        pass
for menu in my_dataset.keys():
    doWork(my_dataset[menu])

So basically, do what I need to do with the five items and delete them from the dataset. I'm comfortable with doing this, since I'm not using said dataset after this block of code. I don't delete the remaining ones after I do work on them, because that's unnecessary. Garbage collection will just blow away the whole dataset after the function's been completed, right?

I had exactly the same problem and devised a lightweight general solution:

from collections import OrderedDict

def make_custom_sort(orders):
    orders = [{k: -i for (i, k) in enumerate(reversed(order), 1)} for order in orders]
    def process(stuff):
        if isinstance(stuff, dict):
            l = [(k, process(v)) for (k, v) in stuff.items()]
            keys = set(stuff)
            for order in orders:
                if keys.issuperset(order):
                    return OrderedDict(sorted(l, key=lambda x: order.get(x[0], 0)))
            return OrderedDict(sorted(l))
        if isinstance(stuff, list):
            return [process(x) for x in stuff]
        return stuff
    return process

First, you create an instance of a custom-order sorting function:

custom_sort = make_custom_sort([ ["Admin", "Groups", "Network", "Subnets", "Entries"] ])

Now, the actual sorting:

result = custom_sort(my_dataset)

The missing keys are rejected at the end in an unspecified order. Note that this closure is recursive. As indicated by the double brackets, you could specify as many sort orders as the various dictionaries nested in your structure would require.

Project on GitHub: https://github.com/laowantong/customsort

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM