ランクごとのランク形式をOpenSTV BLT形式に変換します
質問
私は最近、アンケートを使用して、さまざまなソフトウェアコンポーネントの重要性に関する一連の意見を集めました。何らかの形のコンドルセット投票方法が全体的なランクを得るための最良の方法であると考えて、私はそれを分析するために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)-liner to convertive:
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)])