1

I have the following list of lists of "category" objects in a variable called "category_tree", which is a list:

[[<Category: State>, <Category: County>, <Category: Chicago>], 
[<Category: Animal>],
[<Category: State>, <Category: County>], 
[<Category: State>, <Category: County>, <Category: NYC>], 
[<Category: Animal>, <Category: Fish>], 
[<Category: State>, <Category: County>, <Category: LA>], 
[<Category: Animal>, <Category: Frog>, <Category: TreeFrog>, <Category: Fred>]]

I need to sort the top-level list by the .name properties of the underlying lists. I do not want to sort the underlying lists, just the top-level list.

Assuming the .name elements match what is listed here, this is what I'm trying to get:

[[<Category: Animal>], 
[<Category: Animal>, <Category: Fish>], 
[<Category: Animal>, <Category: Frog>, <Category: TreeFrog>, <Category: Fred>]
[<Category: State>, <Category: County>], 
[<Category: State>, <Category: County>, <Category: Chicago>],
[<Category: State>, <Category: County>, <Category: LA>], 
[<Category: State>, <Category: County>, <Category: NYC>]]

I can sort them by the first or the last column with:

category_tree.sort(key=lambda x: x[0].name)
category_tree.sort(key=lambda x: x[-1].name)

But the problem I'm running into is that they have variable numbers of columns, so I can't sort them this way for all internal columns.

What is the best way to do this?

2
  • What are you trying to achieve with this category tree? Seems more logical to use a dictionary for these type of things. Commented May 27, 2020 at 14:17
  • As far as what I'm trying to achieve -- I'm dealing with outputs from a django website back-end that I get in this form, and I can't change that part of it. I could convert them to some other form and then back to this, if needed. In the end, I just need to sort them. Commented May 27, 2020 at 14:24

1 Answer 1

3

A slighty modified example, with a possible solution:

class Category:
    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return self.name

items = [
    [Category('State'), Category('County'), Category('Chicago')],
    [Category('Animal')],
    [Category('State'), Category('County')],
    [Category('Animal'), Category('Frog')],
    [Category('Animal'), Category('Fish'), Category('Dog')],
]

items.sort(key=lambda x: [item.name for item in x])
print(items)

results in

[[Animal], [Animal, Fish, Dog], [Animal, Frog], [State, County], [State, County, Chicago]]

This relies on the ability of Python to compare lists directly, provided the individual items in the list can be compared properly. For integers, floats and strings, that is not a problem. For a (basic) class, it is, since it not defined by default.

If you have access to the Category class (i.e., you wrote it yourself), you can override __eq__ and other magic comparison methods, which makes things a lot simpler (see e.g. Compare object instances for equality by their attributes ).

With help from the functools module:

from functools import total_ordering

@total_ordering 
class Category:
    def __init__(self, name):
        self.name = name

    def __eq__(self, other):
        return self.name == other.name

    def __lt__(self, other):
        return self.name < other.name

    def __repr__(self):
        return self.name

And then simply:

items.sort()

(items as before).

With the same result: [[Animal], [Animal, Fish, Dog], [Animal, Frog], [State, County], [State, County, Chicago]].

Sign up to request clarification or add additional context in comments.

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.