В Python, как вы сохраняете группировку, когда вы сортируете по одному значению, а затем другому? - PullRequest
2 голосов
/ 08 июня 2011

Данные выглядят так:

Idx, группа оценки 5 0,85 Европа8 0,77 Австралия12 0,70 С.Америка13 0,71 Австралия42 0,82 Европа45 0,90 Азия65 0,91 Азия73 0,72 С.Америка77 0,84 Азия

Необходимо выглядеть следующим образом:

Idx Score group 65 0,91 Азия77 0,84 Азия45 0,73 Азия12 0,87 С.Америка73 0,72 С.Америка5 0,85 Европа42 0,82 Европа8 0,83 Австралия13 0,71 Австралия

Посмотрите, как у Азии самый высокий балл, и он показывает мне все баллы Азии, затем за ней следует группа, которая имеет 2-й самый высокий балл, и так далее?Мне нужно сделать это на Python.Это очень отличается от сортировки по одному элементу, а затем по другому.Пожалуйста помоги.Извините, если этот вопрос является излишним.Я почти не знаю, как спросить это, не говоря уже о поиске.

У меня был словарь, так что dict = {5: [0.85, Европа], 8: [0.77, Австралия] ...}И я сделал функцию, которая пыталась проанализировать данные:

def sortResults(dict):
   newDict = {}
   for k,v in dict.items():
      if v[-1] in newDict:
         sorDic[v[-1]].append((k,float(v[0]),v[1]))
      else:
         newDict[v[-1]] = [(k,float(v[0]),v[1])]
   for k in newDict.keys():
      for resList in newDict[k]:
         resList = sorted(resList,key=itemgetter(1),reverse=True)
   return sorDic

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

Ответы [ 5 ]

2 голосов
/ 08 июня 2011

Я бы просто заполнил словарь с максимальным значением для каждой группы, а затем отсортировал бы по максимальному значению в группе с последующим индивидуальным счетом.Как это:

data = [
  (5 , 0.85, "Europe"),
  (8 , 0.77, "Australia"),
  (12, 0.70, "S.America"),
  (13, 0.71, "Australia"),
  (42, 0.82, "Europe"),
  (45, 0.90, "Asia"),
  (65, 0.91, "Asia"),
  (73, 0.72, "S.America"),
  (77, 0.84, "Asia")
]

maximums_by_group = dict()

for indx, score, group in data:
    if group not in maximums_by_group or maximums_by_group[group] < score:
        maximums_by_group[group] = score

data.sort(key=lambda e: (maximums_by_group[e[2]], e[1]), reverse=True)

for indx, score, group in data:
    print indx, score, group

Это дает ожидаемый результат

65 0.91 Asia
77 0.84 Asia
45 0.73 Asia
12 0.87 S.America
73 0.72 S.America
5 0.85 Europe
42 0.82 Europe
8 0.83 Australia
13 0.71 Australia
0 голосов
/ 08 июня 2011

Самый простой способ сделать это - сбросить данные в список, потому что словари python не отсортированы. Затем используйте собственный алгоритм timsort в python, который сохраняет прогоны или группировки во время сортировки.

Итак, ваш код будет выглядеть примерно так:

data = [[ 5, 0.85, "Europe"],
        [ 8, 0.77, "Australia"],
        [12, 0.70, "S.America"],
        [13, 0.71, "Australia"],
        [42, 0.82, "Europe"],
        [45, 0.90, "Asia"],
        [65, 0.91, "Asia"],
        [73, 0.72, "S.America"],
        [77, 0.84, "Asia"]]

data.sort(key=lambda x: x[1], reverse=True)
data.sort(key=lambda x: x[2].upper())

Это даст:

[65, 0.91, 'Asia']
[45, 0.90, 'Asia']
[77, 0.84, 'Asia']
[8, 0.77, 'Australia']
[13, 0.71, 'Australia']
[5, 0.85, 'Europe']
[42, 0.82, 'Europe']
[73, 0.72, 'S.America']
[12, 0.70, 'S.America']
0 голосов
/ 08 июня 2011

Мне нравится itertools и Оператор :

from itertools import groupby, imap
from operator import itemgetter

def sort_by_max(a_list):
    index, score, group = imap(itemgetter, xrange(3))
    a_list.sort(key=group)
    max_index = dict(
        (each, max(imap(index, entries)))
            for each, entries in groupby(a_list, group)
    )
    a_list.sort(key=lambda x:(-max_index[group(x)], -score(x)))

Используется так:

the_list = [
    [5, 0.85, 'Europe'],
    [8, 0.77, 'Australia'],
    [12, 0.87, 'S.America'],
    [13, 0.71, 'Australia'],
    [42, 0.82, 'Europe'],
    [45, 0.90, 'Asia'],
    [65, 0.91, 'Asia'],
    [73, 0.72, 'S.America'],
    [77, 0.84, 'Asia']
]
sort_by_max(the_list)
for each in the_list:
    print '{0:2} : {1:<4} : {2}'.format(*each)

дает:

65 : 0.91 : Asia
45 : 0.9  : Asia
77 : 0.84 : Asia
12 : 0.87 : S.America
73 : 0.72 : S.America
 5 : 0.85 : Europe
42 : 0.82 : Europe
 8 : 0.77 : Australia
13 : 0.71 : Australia

[EDIT]

Если подумать, мне также нравятся defaultdict и max:

from collections import defaultdict

def sort_by_max(a_list):
    max_index = defaultdict(int)
    for index, score, group in a_list:
        max_index[group] = max(index, max_index[group])
    a_list.sort(key=lambda (index, score, group):(-max_index[group], -score))
0 голосов
/ 08 июня 2011

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

data = [[ 5, 0.85, "Europe"],
        [ 8, 0.77, "Australia"],
        [12, 0.70, "S.America"],
        [13, 0.71, "Australia"],
        [42, 0.82, "Europe"],
        [45, 0.90, "Asia"],
        [65, 0.91, "Asia"],
        [73, 0.72, "S.America"],
        [77, 0.84, "Asia"]]

groups = {}
for idx, score, group in data:
    try:
        groups[group].append((idx, score, group))
    except KeyError:
        groups[group] = [(idx, score, group)]

for group in sorted((group for group in groups.keys()),
                    key = lambda g : -max(x[1] for x in groups[g])):
    for idx, score, group in sorted(groups[group], key = lambda g : -g[1]):
        print idx, score, group

Окончательный результат

65 0.91 Asia
45 0.9  Asia
77 0.84 Asia
 5 0.85 Europe
42 0.82 Europe
 8 0.77 Australia
13 0.71 Australia
73 0.72 S.America
12 0.7  S.America

это отличается от того, что вы предоставили, но для результатов в вашем вопросе, я думаю, у вас есть опечатка, потому что оценка 0.87 для S.America отсутствует во всех входных данных.

0 голосов
/ 08 июня 2011

Я думаю, что есть лучший способ перебора, чем у меня здесь, но это работает:

from operator import itemgetter

dataset = [
    { 'idx': 5, 'score': 0.85, 'group': 'Europe' },
    { 'idx': 8, 'score': 0.77, 'group': 'Australia' },
    { 'idx': 12, 'score': 0.70, 'group': 'S.America' },
    { 'idx': 13, 'score': 0.71, 'group': 'Australia' },
    { 'idx': 42, 'score': 0.82, 'group': 'Europe' },
    { 'idx': 45, 'score': 0.90, 'group': 'Asia' },
    { 'idx': 65, 'score': 0.91, 'group': 'Asia' },
    { 'idx': 73, 'score': 0.72, 'group': 'S.America' }
]

score_sorted = sorted(dataset, key=itemgetter('score'), reverse=True)

group_score_sorted = []
groups_completed = []
for score in score_sorted:
    group_name = score['group']
    if not group_name in groups_completed:
        groups_completed.append(group_name)

        for group in score_sorted:
            if group['group'] = group_name:
                group_score_sorted.append(group)

#group_score_sorted now contains sorted list
...