Сортировать список по ключу и отсортировать другой список так же, как первый? - PullRequest
0 голосов
/ 21 февраля 2019

Например, есть три списка:

unsorted_key = ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']
sorted_key = ['e', 'i', 'o', 'p', 'q', 'r', 't', 'u', 'w', 'y']
ciphertext = [
              ['u', 't', 'x', 'e'],
              ['p', 'r', 'k', 'p'],
              ['v', 'n', 'x', 'a'],
              ['n', 'h', 'e', 'x'],
              ['x', 'h', 'm', 's'],
              ['l', 'x', 'c', 'x'],
              ['x', 'c', 'y', 'a'],
              ['t', 'u', 'o', 'x'],
              ['e', 'r', 'm', 'e'],
              ['y', 'y', 'e', 'x']
             ]

Можно ли взять порядок sorted_key и отсортировать его в unsorted_key, взять порядок зашифрованного текста и отсортировать его идентичным образом?

При перемещении 'q' из sorted_key [4] в sorted_key [0], он должен переместить зашифрованный текст [4] в зашифрованный текст [0].

  • Все три списка всегда будутбыть равной длины.
  • sorted_key и unsorted_key никогда не будут иметь повторяющихся элементов.
  • Sorted_key всегда будет отсортированной версией unsorted_key.

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

sorted_key, ciphertext = (list(i) for i in zip(*sorted(zip(sorted_key, ciphertext), key=generate(unsorted_key))))

Но яна самом деле не знаю, как работают zip () или лямбда-функции или как сделать пользовательский порядок сортировки в один, или можно ли даже вернуть его для использования в sorted ().Я действительно не могу обернуться вокруг этой проблемы, поэтому любая помощь будет принята с благодарностью!

Ответы [ 4 ]

0 голосов
/ 21 февраля 2019

Встроенный sorted с пользовательским ключом может сделать это за вас:

sorted(ciphertext, key=lambda x: unsorted_key.index(sorted_key[ciphertext.index(x)]))

Вывод:

[['x', 'h', 'm', 's'], 
 ['e', 'r', 'm', 'e'], 
 ['u', 't', 'x', 'e'], 
 ['l', 'x', 'c', 'x'], 
 ['x', 'c', 'y', 'a'], 
 ['y', 'y', 'e', 'x'], 
 ['t', 'u', 'o', 'x'], 
 ['p', 'r', 'k', 'p'], 
 ['v', 'n', 'x', 'a'], 
 ['n', 'h', 'e', 'x']]

Лямбда в основном сводится к:

  1. Найти текущий индекс
  2. Найти значение текущего индекса в sorted_key
  3. Найти индекс sorted_key в unsorted_key
  4. Сортировать его

Единственное, в чем я не совсем уверен, так это зачем вам "сортировать" sorted_key, если конечный результат идентичен unsorted_key?Просто sorted_key = unsorted_key[:] достаточно просто, если это так.Но если вам действительно нужно также отсортировать sorted_key, вы можете сделать это (на самом деле lambda будет проще):

ciphertext, sorted_key = map(list, zip(*sorted(zip(ciphertext, sorted_key), key=lambda x: unsorted_key.index(x[1]))))

ciphertext
[['x', 'h', 'm', 's'], 
 ['e', 'r', 'm', 'e'], 
 ['u', 't', 'x', 'e'], 
 ['l', 'x', 'c', 'x'], 
 ['x', 'c', 'y', 'a'], 
 ['y', 'y', 'e', 'x'], 
 ['t', 'u', 'o', 'x'], 
 ['p', 'r', 'k', 'p'], 
 ['v', 'n', 'x', 'a'], 
 ['n', 'h', 'e', 'x']]

sorted_key
['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p']
0 голосов
/ 21 февраля 2019

Я не уверен, что понял, но ...

Сначала определите ходы (может быть наоборот, мне не понятно):

moves = [ [i, sorted_key.index(c)] for i, c in enumerate(unsorted_key) ]
#=> [[0, 4], [1, 8], [2, 0], [3, 5], [4, 6], [5, 9], [6, 7], [7, 1], [8, 2], [9, 3]]

Может бытьПоменяйте местами элементы в [i, sorted_key.index(c)].

Применить ходы к получателю (res):

res = [ None for _ in range(len(ciphertext))]
for a, b in moves:
  res[a] = ciphertext[b]

Таким образом, вывод должен быть:

for line in res:
  print(line)

# ['x', 'h', 'm', 's']
# ['e', 'r', 'm', 'e']
# ['u', 't', 'x', 'e']
# ['l', 'x', 'c', 'x']
# ['x', 'c', 'y', 'a']
# ['y', 'y', 'e', 'x']
# ['t', 'u', 'o', 'x']
# ['p', 'r', 'k', 'p']
# ['v', 'n', 'x', 'a']
# ['n', 'h', 'e', 'x']


Для времени выполнения теста
import timeit, functools

def custom_sort(ciphertext, sorted_key, unsorted_key):
  return [ ciphertext[b] for _, b in [ [i, sorted_key.index(c)] for i, c in enumerate(unsorted_key) ] ]


custom_sort = timeit.Timer(functools.partial(custom_sort, ciphertext, sorted_key, unsorted_key))

print(custom_sort.timeit(20000))
0 голосов
/ 21 февраля 2019

Эффективный подход к решению этой проблемы за линейное время заключается в создании dict, который сопоставляет ключи с индексами sorted_key, а затем создает сопоставление, которое отображает индексы unsorted_key в индексы sorted_key на основете же ключи, так что вы можете выполнить итерацию индекса в диапазоне длины ciphertext, чтобы сгенерировать список в отображенном порядке:

order = dict(map(reversed, enumerate(sorted_key)))
mapping = {i: order[k] for i, k in enumerate(unsorted_key)}
print([ciphertext[mapping[i]] for i in range(len(ciphertext))])

Это приводит к:

[['x', 'h', 'm', 's'], ['e', 'r', 'm', 'e'], ['u', 't', 'x', 'e'], ['l', 'x', 'c', 'x'], ['x', 'c', 'y', 'a'], ['y', 'y', 'e', 'x'], ['t', 'u', 'o', 'x'], ['p', 'r', 'k', 'p'], ['v', 'n', 'x', 'a'], ['n', 'h', 'e', 'x']]
0 голосов
/ 21 февраля 2019

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

pairs = zip(unsorted_key, ciphertext)
sorted_key = []
sorted_ciphertexts = []
for t in sorted(pairs):
   sorted_key.append(t[0])
   sorted_ciphertexts.append(t[1])

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

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