Pregunta

Recientemente reuní, utilizando un cuestionario, un conjunto de opiniones sobre la importancia de varios componentes de software. Sentiendo que alguna forma de método de votación de Condorcet sería la mejor manera de obtener un rango general, opté por usar OpenStv para analizarlo.


Mis datos están en formato tabular, delimitan el espacio y se parece más o menos a:

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

En este formato, el número indica el rango y el orden de secuencia indica al candidato.Cada "candidato" tiene un rango (requerido) de 1 a 7, donde un 1 significa más importante y un 7 significa menos importante. No se permiten duplicados.

Este formato me pareció la forma más natural de representar el resultado, siendo una representación directa del formato de votación.


El formato OpenStv/BLT utiliza un método diferente para representar la misma información, conceptualmente de la siguiente manera:

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

El formato de archivo numérico real utiliza el índice (basado en 1) del candidato, en lugar de la etiqueta, por lo que es más como:

7 2 4 3 1 6 5    # Same ballots as before.
5 2 7 1 4 3 6    # A -> 1, G -> 7

En este formato, el número indica al candidato, y el orden de secuencia indica el rango. El formato BLT real, real, también incluye un peso líder y un siguiente cero para indicar el final de cada boleta, del cual no me importa demasiado por esto.


Mi pregunta es, ¿Cuál es la forma más elegante de convertir del primer formato al segundo (numérico)?

¿Fue útil?

Solución

Aquí está mi solución en Python, y funciona bien, pero se siente un poco torpe. Estoy seguro de que hay una forma más limpia (¿quizás en otro idioma?)

Esto me llevó más tiempo de lo que debería tener que entender ayer por la tarde, por lo que tal vez alguien más también pueda usar esto.

Dado:

ballot = '5 2 4 3 7 6 1'

Python One (ish) -liner para convertirlo:

rank = [i for r,i in sorted((int(r),i+1) for i,r in enumerate(ballot.split())]
rank = " ".join(rank)

Alternativamente, en una forma un poco más comprensible:

# 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)])
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top