Python эффективный вид параллельных списков в словаре - PullRequest
0 голосов
/ 02 октября 2018

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

unsorted_my_dict = {
   'key_one': [1,6,2,3],
   'key_two': [4,1,9,7],
   'key_three': [1,2,4,3],
   ...
}
sorted_my_dict = {
   'key_one': [1,6,3,2],
   'key_two': [4,1,7,9],
   'key_three': [1,2,3,4],
   ...
}

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

Нужно сделать это с ванильным Python, без сторонних зависимостей.

Редактировать 1: Что я имею в виду параллельно?Я имею в виду, что если я сортирую key_three, для чего требуется поменять местами последние два значения, то во всех остальных списках в словаре также будут поменяны последние два значения.

Редактировать 2: Python 3.4 специально

Ответы [ 3 ]

0 голосов
/ 02 октября 2018

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

sorted_value_groups = sorted(zip(*unsorted_my_dict.values()), key=lambda _, it=iter(unsorted_my_dict['key_three']): next(it))
sorted_values = zip(*sorted_value_groups)
sorted_my_dict = {k: list(newvals) for k, newvals in zip(unsorted_my_dict, sorted_values)}

Совсем не чисто, я в основном простоопубликовал это для приколов.Одна строка:

sorted_my_dict = {k: list(newvals) for k, newvals in zip(unsorted_my_dict, zip(*sorted(zip(*unsorted_my_dict.values()), key=lambda _, it=iter(unsorted_my_dict['key_three']): next(it))))}

Это работает, потому что, хотя dict порядок итераций не гарантирован до 3.7, порядок гарантированно будет повторяться для неизмененного dict.Точно так же функция key выполняется в порядке от начала до конца, поэтому извлечение ключа повторной итерацией безопасно.Мы просто отсоединяем все значения, группируем их по индексу, сортируем группы по ключу индекса, перегруппируем их по ключу и снова присоединяем их к их исходным ключам.

Вывод выполняется точно в соответствии с запросом (и порядокоригинальные ключи сохраняются в CPython 3.6 или любом Python 3.7 или выше):

sorted_my_dict = {
   'key_one': [1,6,3,2],
   'key_two': [4,1,7,9],
   'key_three': [1,2,3,4]
}
0 голосов
/ 02 октября 2018

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

unsorted_my_dict = {
'key_one': [1, 6, 2, 3],
'key_two': [4, 1, 9, 7],
'key_three': [1, 2, 4, 3],
}


def sort_parallel_by_key(my_dict, key):
    def sort_by_indices(idx_seq):
        return {k: [v[i] for i in idx_seq] for k, v in my_dict.items()}

    indexes = [idx for idx, _ in sorted(enumerate(my_dict[key]), key=lambda foo: foo[1])]
    return sort_by_indices(indexes)


print(sort_parallel_by_key(unsorted_my_dict, 'key_three'))
0 голосов
/ 02 октября 2018

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

my_dict = {
   'key_one': [1,6,2,3],
   'key_two': [4,1,9,7],
   'key_three': [1,2,4,3],
}


def parallel_sort(d, key):
    index_order = [i for i, _ in sorted(enumerate(d[key]), key=lambda x: x[1])]
    return {k: [v[i] for i in index_order] for k, v in d.items()}

print(parallel_sort(my_dict, 'key_three'))

Выход

{'key_one': [1, 6, 3, 2],
 'key_two': [4, 1, 7, 9],
 'key_three': [1, 2, 3, 4]}
...