Преобразовать формат ранга на кандидат в формат openstv blt
Вопрос
Недавно я собрал, используя вопросник, набор мнений о важности различных компонентов программного обеспечения. Полагая, что некоторая форма метода голосования Condorcet будет лучшим способом получить общий ранг, я решил использовать OpenSTV для его анализа.
Мои данные находятся в табличном формате, распределили пространство и более или менее похожи на:
A B C D E F G # Candidates
5 2 4 3 7 6 1 # First ballot. G is ranked first, and E is ranked 7th
4 2 6 5 1 7 3 # Second ballot
etc
В этом формате число указывает ранг, а порядок последовательности указывает кандидата.Каждый «кандидат» имеет ранг (требуемый) от 1 до 7, где 1 означает наиболее важное, а 7 означает наименее важное. Дубликаты не допускаются.
Этот формат показался мне самым естественным способом представления вывода, будучи прямым представлением формата голосования.
В формате OpenStv/BLT используется другой метод представления одной и той же информации, концептуально следующим образом:
G B D C A F E # Again, G is ranked first and E is ranked 7th
E B G A D C F #
etc
Фактическое числовое формат файлов использует (1) индекс кандидата, а не метку, и поэтому больше похож на:
7 2 4 3 1 6 5 # Same ballots as before.
5 2 7 1 4 3 6 # A -> 1, G -> 7
В этом формате число указывает кандидата, а порядок последовательности указывает ранг. Анкет Фактический, реальный, BLT -формат также включает в себя ведущий вес и следующий нуль, чтобы указать конец каждого избирательного бюллетеня, о котором мне не все равно.
Мой вопрос, Какой самый элегантный способ преобразовать из первого формата в (числовый) второй?
Решение
Вот мое решение в Python, и оно работает нормально, но кажется немного неуклюжим. Я уверен, что есть более чистый путь (возможно, на другом языке?)
Это заняло у меня больше времени, чем должно было обернуть мою голову вчера днем, так что, возможно, кто -то другой тоже может использовать это.
Данный:
ballot = '5 2 4 3 7 6 1'
Python One (iSh) -Nerer для преобразования:
rank = [i for r,i in sorted((int(r),i+1) for i,r in enumerate(ballot.split())]
rank = " ".join(rank)
В качестве альтернативы, в немного более понятной форме:
# Split into a list and convert to integers
int_ballot = [int(x) for x in ballot.split()]
# This is the important bit.
# enumerate(int_ballot) yields pairs of (zero-based-candidate-index, rank)
# Use a list comprehension to swap to (rank, one-based-candidate-index)
ranked_ballot = [(rank,index+1) for index,rank in enumerate(int_ballot)]
# Sort by the ranking. Python sorts tuples in lexicographic order
# (ie sorts on first element)
# Use a comprehension to extract the candidate from each pair
rank = " ".join([candidate for rank,candidate in sorted(ranked_ballot)])