Home > Software engineering >  Sort dictionary by multiple values, where amount of values can vary
Sort dictionary by multiple values, where amount of values can vary

Time:01-17

To come straight to the point:

def sortBy(dict, byWhat):

  # byWhat is a list of 1 - 10 strings, which can include any of allAttributes
  # allAttributes = ['name', 'kingdom', 'diff', 'tier', 'type', 'founder', 'prover', 'server', 'extra', 'link']
  # the lower the index, the higher the sorting priority -> byWhat = ['name', 'diff'] then sort by name first and then if names are the same by diff
  
  # dict has the name as key and then allAttributes above in order as a list for the key's value, so for example:
  # dict[Jump] = [Jump, Mushroom Kingdom, 10/10, Triple Jump, Dude, Dude2, Main Server, Cool jump description, https://twitter.com]
  # All dictionary entries have those 10 attributes, no exceptions
  
  return dict # but sorted

I tried for a while but where my knowledge ends is sorting by a varying size of specifiers with lambda. I can also not just call the function multiple times, because then it won't sort by two attributes, but by the last attribute the function got called with.

CodePudding user response:

You can convert dict to list of (key, value) tuples and use list.sort(key) method and utilizing functools.cmp_to_key define key as compare function and then "inject" byWhat parameter into compare function using functools.partial

from functools import cmp_to_key, partial

allAttributes = ["name", "age"]

def sortBy(d, byWhat):
    def cmp(a, b, byWhat):
        for k in byWhat:
            index = allAttributes.index(k)
            if a[1][index] != b[1][index]:
                return -1 if a[1][index] < b[1][index] else 1
        return 0
    items = list(d.items())
    items.sort(key=cmp_to_key(partial(cmp, byWhat=byWhat)))
    return dict(items)

if __name__ == "__main__":
    d = {
        "foo": ["John", 12],
        "bar": ["Adam", 12],
        "baz": ["John", 10],
    }
    print(sortBy(d, ["name", "age"]))

CodePudding user response:

You can convert dict to list of (key, value) tuples, map byWhat into indexes and use list.sort(key) where key is lambda returning list of attributes to sort by.

allAttributes = ["name", "age"]

def sortBy(d, byWhat):
    indexes = [allAttributes.index(k) for k in byWhat]
    items = list(d.items())
    items.sort(key=lambda item: [item[1][index] for index in indexes])
    return dict(items)

if __name__ == "__main__":
    d = {
        "foo": ["John", 12],
        "bar": ["Adam", 12],
        "baz": ["John", 10],
    }
    print(sortBy(d, ["name", "age"]))
  • Related