1

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?

3
  • 1
    Can you explain more about why you need to do this? What is the context of this problem? Commented Nov 14, 2012 at 16:48
  • 3
    Dictionaries in python are not ordered. Dictionaries are hash tables, not sequences. Commented Nov 14, 2012 at 16:48
  • 2
    If it's because you're printing your dictionaries directly, you're doing things wrong. Consider print('Admin: {Admin}, Groups: {Groups}, ...', **your_dict) Commented Nov 14, 2012 at 16:50

5 Answers 5

4

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', [])])
Sign up to request clarification or add additional context in comments.

Comments

3

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

Comments

1

Store the data as a list of pairs.

1 Comment

Yeah, a list of single entry dictionaries would do it.
0

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?

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.