Сортировка словаря с несколькими значениями размера

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

Словарь:

my_dict = {
    '1' : ['Red', 'McDonald\'s'],
    '2' : [['Orange', 'Wendy\'s'], ['Purple', 'Cookout']],
    '3' : ['Yellow', 'Longhorn'],
    '4' : ['Green', 'Subway'],
    '5' : ['Blue', 'Chipotle'],
    '6' : ['Indigo', 'Taco Bell'],
    '7' : [['Violet', 'Steak n Shake'], ['Dark Red', 'Five Guys']],
    '8' : ['Dark Orange', 'Wendy\'s'],
    '9' : ['Aqua', 'Firehouse Subs'],
    '10' : ['Magenta', 'McDonald\'s'],
}

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

Пример печати по номеру:

1:
    Red, McDonald's

2:
    Orange, Wendy's
    Purple, Cookout

3:
    Yellow, Longhorn

...

Пример печати по цветам:

Aqua:
    Firehouse Subs, 9

Blue:
    Chipotle, 5

Dark Orange:
    Wendy's, 8

...

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

sorted_number = []
for key, value in my_dict.items():
    if len(value[0][0]) > 1:
        working_list = (key, value[0][0], value[0][1], value[1][0], value[1][1])
        sorted_number.append(working_list)
    else:
        working_list = (key, value[0], value[1])
        sorted_number.append(working_list)

sorted_years = sorted(sorted_years, key=lambda y: y[0][0])
for i in sorted_years:
    print('{}:'.format(i[0]))
    if len(i) > 3:
         print('\t{}, {}'.format(i[1], i[2])
         print('\t{}, {}'.format(i[3], i[4]))
    else:
         print('\t{}, {}'.format(i[1], i[2]))

Поскольку некоторые значения представляют собой несколько списков, оператор if/else определяет, является ли значение одним или двумя списками. Затем это правильно создаст список (число, цвет, ресторан) или (число, цвет, ресторан, цвет, ресторан), который затем может отсортировать список по номеру. Проблема в том, что я пытаюсь отсортировать по цвету или ресторану. Я знаю, что могу сделать список только из трех элементов, чтобы сортировка работала правильно, но когда я перейду к печати, я получу несколько 2 и 7. Тот же результат с рестораном. Кроме того, это не решает проблему нескольких ресторанов. Я искал и тестировал около пяти дней, пытаясь распаковать словарь разными способами, но это самый близкий мне способ решения этой проблемы. Любая помощь приветствуется. Заранее спасибо.

Для ясности вот итерация печати для чисел:

for i in sorted_number:
    print('{}:'.format(i[0]))
    if len(i) > 3:
        print('\t{}, {}'.format(i[1], i[2]))
        print('\t{}, {}'.format(i[3], i[4]))
    else:
        print('\t{}, {}'.format(i[1], i[2]))

person Peperm1nt    schedule 22.06.2018    source источник
comment
Пробовали ли вы читать этот python.org/dev/peps/pep-0265   -  person Nitish Kumar    schedule 22.06.2018
comment
@NitishKumar Значения могут быть одним или двумя списками. Если есть что-то, что я упускаю из виду, решение состоит в том, чтобы преобразовать словарь в список из трех элементов, а затем выполнить сортировку.   -  person Peperm1nt    schedule 22.06.2018
comment
Возможно, вы могли бы использовать JSON   -  person BioFrank    schedule 22.06.2018
comment
Как вы хотите расположить при сортировке по цвету элемент '7' : [['Violet', 'Steak n Shake'], ['Dark Red', 'Five Guys']]? Должен ли он идти после '8' : ['Dark Orange', 'Wendy\'s'] (используя 'Dark Red') или после '1' : ['Red', 'McDonald\'s'] (используя 'Violet')?   -  person Serge Ballesta    schedule 22.06.2018
comment
@SergeBallesta На самом деле не стоит беспокоиться о размещении, если при повторении списка или кортежа вы можете распечатать информацию, как описано. Мои мысли состояли в том, чтобы составить список вроде (5, Blue, Chipotle), но проблема в том, что когда вы идете на печать, у вас будут дубликаты в сортировке (например, 2 McDonald's). Для повторяющихся записей для сортировки вы должны печатать следующим образом: McDonald's: Red, 1 Magenta, 10 Я не могу правильно отформатировать комментарий, чтобы показать правильный отступ.   -  person Peperm1nt    schedule 22.06.2018


Ответы (2)


Первый шаг — преобразовать словарь в список и гомогенизировать значение словаря в виде массива кортежей. Затем с помощью функции groupBy из модуля itertools вы можете группировать по выбранный параметр.

class RestourantSorter:
    def __init__(self, source):
        self._rList = []
        """ Dict to list [(key, color, restourant name), ....] """
        for key, value in source.items():
            for color, rest in value if isinstance(value[0], list) else [value]:
                self._rList.append((key,color,rest))

    def _byIndex(self, x):
        return int(x[0])
    def _byColor(self, x):
        return x[1]
    def _byName(self, x):
        return x[2]

    def sort(self, sortFn):
        """ Sorted data [(key, [... values ...]), ....] """
        groups = []
        data = sorted(self._rList, key=sortFn)
        for k, g in groupby(data, sortFn):
            groups.append((k, list(g)))
        return groups

    def sortByIndex(self):
        return self.sort(self._byIndex)
    def sortByColor(self):
        return self.sort(self._byColor)
    def sortByName(self):
        return self.sort(self._byName)

Рабочий REPL

person Vanojx1    schedule 22.06.2018
comment
Вы замечательный человек! Я все еще учусь, и до сих пор в классе ничего не касалось init и self для создания класса. Мы слегка затронули тему построения классов, и, честно говоря, я, возможно, определил что-то всего один или два раза. Это мой первый урок программирования, и мне определенно нужно будет подробнее изучить его создание; если это даже правильная терминология. Я понимаю около 90% того, что происходит с этим классом; однако мне нужно заглянуть в себя и init, чтобы полностью все понять. Еще раз спасибо! - person Peperm1nt; 22.06.2018

Когда вы хотите изменить или применить другую индексацию, словарь не идеален. У него может быть только один ключ. Если использовать номер как ключ, переход на индексацию по цвету затруднен. Словари оптимизированы не для этого.

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

import pandas as pd
from itertools import chain

chainer = chain.from_iterable

# calculate numeric keys including repeats, flat list
keys = list(chainer([k]*(len(v) if isinstance(v[0], list) else 1) \
                    for k, v in my_dict.items()))

# calculate color-name combinations, list of lists, each sublist of length 2
vals = list(chainer((v if isinstance(v[0], list) else [v] \
                    for v in my_dict.values())))

# create dataframe
df = pd.DataFrame(vals, columns=['color', 'name'], index=keys)

Затем вы можете сгруппировать по числовому ключу, цвету и т. д. для желаемых результатов, для которых на SO доступно множество решений. Возможна сортировка, вывод в dict или итерация с print.

print(df)

          color            name
1           Red      McDonald's
2        Orange         Wendy's
2        Purple         Cookout
3        Yellow        Longhorn
4         Green          Subway
5          Blue        Chipotle
6        Indigo       Taco Bell
7        Violet   Steak n Shake
7      Dark Red       Five Guys
8   Dark Orange         Wendy's
9          Aqua  Firehouse Subs
10      Magenta      McDonald's
person jpp    schedule 22.06.2018