Сортировка списка словарей объектов по значениям словаря - PullRequest
2 голосов
/ 29 июля 2009

Это связано с различными другими вопросами о сортировке значений словарей, которые я читал здесь, но я не нашел ответа. Я новичок и, возможно, я просто не видел ответа, поскольку он касается моей проблемы.

У меня есть эта функция, которую я использую в качестве пользовательского фильтра Django для сортировки результатов из списка словарей. На самом деле, на основную часть этой функции был дан ответ в связанном вопросе о stackoverflow.

def multikeysorting(dict_list, sortkeys):
    from operator import itemgetter

    def multikeysort(items, columns):
        comparers = [ ((itemgetter(col[1:]), -1) if col.startswith('-') else (itemgetter(col), 1)) for col in columns]

        def sign(a, b):
            if a < b:   return -1
            elif a > b: return 1
            else:       return 0

        def comparer(left,right):
            for fn, mult in comparers:
                result = sign(fn(left), fn(right))
                if result:
                    return mult * result
            else:
                return 0

        return sorted(items, cmp=comparer)

    keys_list = sortkeys.split(",")
    return multikeysort(dict_list, keys_list)

Этот фильтр называется в Django следующим образом:

{% for item in stats|statleaders_has_stat:"TOT_PTS_Misc"|multikeysorting:"-TOT_PTS_Misc.value,TOT_PTS_Misc.player.last_name" %}

Это означает, что в функцию передаются два словарных значения для сортировки списка словарей. Сортировка работает с ключами словаря, но не со значениями.

Как можно отсортировать и вернуть словарь, отсортировав список словарей с более чем одним значением? В приведенном выше примере сначала по значению, а затем по фамилии.

Вот пример данных:

[{u'TOT_PTS_Misc': < StatisticPlayerRollup: DeWitt, Ash Total Points : 6.0>, 'player': < Player: DeWitt, Ash>}, 
{u'TOT_PTS_Misc': < StatisticPlayerRollup: Ackerman, Luke Total Points : 18.0>, 'player': < Player: Ackerman, Luke>}, 
{u'TOT_PTS_Misc': < StatisticPlayerRollup: Wise, Dan Total Points : 19.0>, 'player': < Player: Wise, Dan>}, 
{u'TOT_PTS_Misc': < StatisticPlayerRollup: Allison, Mike Total Points : 18.0>, 'player': < Player: Allison, Mike>}, 
{u'TOT_PTS_Misc': < StatisticPlayerRollup: Wolford, Alex Total Points : 18.0>, 'player': < Player: Wolford, Alex>}, 
{u'TOT_PTS_Misc': < StatisticPlayerRollup: Okes, Joe Total Points : 18.0>, 'player': < Player: Okes, Joe>}, 
{u'TOT_PTS_Misc': < StatisticPlayerRollup: Grattan, Paul Total Points : 18.0>, 'player': < Player: Grattan, Paul>}]
    

Список должен быть отсортирован следующим образом:

LastName Points
Wise 19.0
Ackerman 18.0
Allison 18.0
Grattan 18.0
Okes 18.0
Wolford 18.0
Hagg 6.0
DeWitt 6.0

TOT_PTS_Misc - это объект, который содержит имя игрока, а также количество очков. (Надеюсь, я объясню это правильно.)

Но должны быть произвольные значения, восходящие или нисходящие. Не всегда одинаковые значения и, возможно, более двух.


Итак, я придумал это решение, но хотел знать, имеет ли оно смысл и есть ли что-то, что следует изменить.

def multikeysorting(dict_list, sortkeys):
    from operator import itemgetter, attrgetter

    klist = sortkeys.split(",")
    vlist = []
    for i in klist:
        vlist.append(tuple(i.split(".")))

    def getkeyvalue(val_list):
        result = []
        for id,val in enumerate(val_list):
            if val[0].startswith('-'):
                if len(val) == 2:
                    result.append((itemgetter(val[0][1:]).attrgetter(val[1]), -1))
                else:
                    att = val[1]
                    for j in val[2:]:
                        att = att + "." + j
                    result.append((itemgetter(val[0][1:]).attrgetter(att), -1))
            else:
                if len(val) == 2:
                    result.append((itemgetter(val[0]).attrgetter(val[1]), 1))
                else:
                    att = val[1]
                    for j in val[2:]:
                        att = att + "." + j
                    result.append((itemgetter(val[0]).attrgetter(att), 1))
        return result

    return sorted(dict_list, key=getkeyvalue(vlist))

Ответы [ 2 ]

2 голосов
/ 30 июля 2009

Вы получаете доступ к ключам с помощью itemgetter и к атрибутам значений с помощью attrgetter.

Итак, после того, как вы извлекли ключ и имена значений, которые вас интересуют, вы можете создать свою функцию ключа:

from operator import attrgetter, itemgetter
itmget = itemgetter('TOT_PTS_Misc')
attget_v = attrgetter('value')
attget_l = attrgetter('last_name')
def keyfunc(x):
    itm = itmget(x)
    return (-attget_v(itm), attget_n(itm))
sorted(dictlist, key=keyfunc)

Это похоже на работу. Это то, что вы спрашиваете? Или я что-то упустил?

0 голосов
/ 29 июля 2009

Насколько я вижу, есть две вещи, которые вам нужно сделать.

Во-первых, проанализировать путь вызова из ключа сортировки, то есть: повернуть 'TOT_PTS_Misc.value' в ('TOT_PTS_Misc','value') Во-вторых,используйте attrgetter аналогично использованию itemgetter для вызываемой части.

Если я не ошибаюсь, itemgetter('TOT_PTS_Misc').attrgetter('value') ДОЛЖЕН быть равен dict['TOT_PTS_Misc'].value

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...