Encontrar votos de la mayoría en-1, 1 y 0 en la lista-Python
if-statement binary (13)
# These are your actual votes
votes = [-1, -1, -1, -1, 0]
# These are the options on the ballot
ballot = (-1, 0, 1)
# This is to initialize your counters
counters = {x: 0 for x in ballot}
# Count the number of votes
for vote in votes:
counters[vote] += 1
results = counters.values().sort()
if len(set(values)) < len(ballot) and values[-1] == values [-2]:
# Return 0 if there''s a tie
return 0
else:
# Return your winning vote if there isn''t a tie
return max(counters, key=counters.get)
¿Cómo encontrar la mayoría de los votos para una lista que puede contener -1s, 1s y 0s?
Por ejemplo, dada una lista de:
x = [-1, -1, -1, -1, 0]
La mayoría es -1, por lo que la salida debería devolver -1
Otro ejemplo, dada una lista de:
x = [1, 1, 1, 0, 0, -1]
El voto mayoritario sería 1
Y cuando tenemos un empate, el voto de la mayoría debe devolver 0, por ejemplo:
x = [1, 1, 1, -1, -1, -1]
Esto también debería devolver cero:
x = [1, 1, 0, 0, -1, -1]
El caso más simple para obtener el voto mayoritario parece resumir la lista y verificar si es negativa, positiva o 0.
>>> x = [-1, -1, -1, -1, 0]
>>> sum(x) # So majority -> 0
-4
>>> x = [-1, 1, 1, 1, 0]
>>> sum(x) # So majority -> 1
2
>>> x = [-1, -1, 1, 1, 0]
>>> sum(x) # So majority is tied, i.e. -> 0
0
Después de la suma, podría hacer este control para obtener la mayoría de votos, es decir:
>>> x = [-1, 1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
1
>>> x = [-1, -1, 1, 1, 0]
>>> majority = -1 if sum(x) < 0 else 1 if sum(x)!=0 else 0
>>> majority
0
Pero como se señaló anteriormente, es feo: Python coloca una declaración if-elif-else en una línea y no en pythonic.
Entonces la solución parece ser
>>> x = [-1, -1, 1, 1, 0]
>>> if sum(x) == 0:
... majority = 0
... else:
... majority = -1 if sum(x) < 0 else 1
...
>>> majority
0
EDITADO
Pero hay casos en que sum()
no funcionará, @ RobertB, por ejemplo
>>> x = [-1, -1, 0, 0, 0, 0]
>>> sum(x)
-2
¡Pero en este caso el voto de la mayoría debería ser 0!
Creo que esto funciona para todos los casos de prueba proporcionados. Por favor, avíseme si hice algo mal.
from collections import Counter
def fn(x):
counts = Counter(x)
num_n1 = counts.get(-1, 0)
num_p1 = counts.get(1, 0)
num_z = counts.get(0, 0)
if num_n1 > num_p1:
return -1 if num_n1 > num_z else 0
elif num_p1 > num_n1:
return 1 if num_p1 > num_z else 0
else:
return 0
Supongo que los votos para 0 cuentan como votos. Entonces la sum
no es una opción razonable.
Pruebe un contador:
>>> from collections import Counter
>>> x = Counter([-1,-1,-1, 1,1,1,1,0,0,0,0,0,0,0,0])
>>> x
Counter({0: 8, 1: 4, -1: 3})
>>> x.most_common(1)
[(0, 8)]
>>> x.most_common(1)[0][0]
0
Entonces podrías escribir código como:
from collections import Counter
def find_majority(votes):
vote_count = Counter(votes)
top_two = vote_count.most_common(2)
if len(top_two)>1 and top_two[0][1] == top_two[1][1]:
# It is a tie
return 0
return top_two[0][0]
>>> find_majority([1,1,-1,-1,0]) # It is a tie
0
>>> find_majority([1,1,1,1, -1,-1,-1,0])
1
>>> find_majority([-1,-1,0,0,0]) # Votes for zero win
0
>>> find_majority([''a'',''a'',''b'',]) # Totally not asked for, but would work
''a''
from collections import Counter
result = Counter(votes).most_common(2)
result = 0 if result[0][1] == result[1][1] else result[0][0]
El manejo de errores para listas de votes
vacías o listas de votes
con una cardinalidad establecida de 1 es trivial y se deja como ejercicio para el lector.
import numpy as np
def fn(vote):
n=vote[np.where(vote<0)].size
p=vote[np.where(vote>0)].size
ret=np.sign(p-n)
z=vote.size-p-n
if z>=max(p,n):
ret=0
return ret
# some test cases
print fn(np.array([-1,-1, 1,1,1,1,0,0,0,0,0,0,0,0]))
print fn(np.array([-1, -1, -1, 1,1,1,0,0]))
print fn(np.array([0,0,0,1,1,1]))
print fn(np.array([1,1,1,1, -1,-1,-1,0]))
print fn(np.array([-1, -1, -1, -1, 1, 0]))
Esta solución se basa en el conteo de las ocurrencias y la clasificación:
import operator
def determineMajority(x):
''''''
>>> determineMajority([-1, -1, -1, -1, 0])
-1
>>> determineMajority([1, 1, 1, 0, 0, -1])
1
>>> determineMajority([1, 1, 1, -1, -1, -1])
0
>>> determineMajority([1, 1, 1, 0, 0, 0])
0
>>> determineMajority([1, 1, 0, 0, -1, -1])
0
>>> determineMajority([-1, -1, 0, 0, 0, 0])
0
''''''
# Count three times
# sort on counts
xs = sorted(
[(i, x.count(i)) for i in range(-1,2)],
key=operator.itemgetter(1),
reverse=True
)
if xs[0][1] > xs[1][1]:
return xs[0][0]
else:
# tie
return 0
if __name__ == ''__main__'':
import doctest
doctest.testmod()
Además, hay una si las declaraciones. Como se mencionó en los comentarios, no está definido qué sucede con
x = [1, 1, 0, 0, -1]
No necesita nada más que los operadores de listas incorporadas y esas cosas, no es necesario importar nada.
votes = [ -1,-1,0,1,0,1,-1,-1] # note that we don''t care about ordering
counts = [ votes.count(-1),votes.count(0),votes.count(1)]
if (counts[0]>0 and counts.count(counts[0]) > 1) or (counts[1]>0 and counts.count(counts[1])>1):
majority=0
else:
majority=counts.index(max(counts))-1 # subtract 1 as indexes start with 0
print majority
La línea 3d pone los conteos de los votos respectivos en una nueva lista, y counts.index () nos muestra en qué posición de la lista encontramos los votos máximos.
Me atrevería a decir que esto debería ser lo más pitónico posible, sin meterse en espeluznantes especuladores.
Upd: reescribió sin cadenas de texto y se actualizó para devolver 0 en caso de varios resultados iguales (no se notó esto en la publicación original), se agregó una IF para el caso si solo un voto, por ejemplo votos = [- 1]
Puede usar statistics.mode si estaba usando python> = 3.4, capturando un StatisticsError
para cuando no tiene un modo único:
from statistics import mode, StatisticsError
def majority(l):
try:
return mode(l)
except StatisticsError:
return 0
La implementación de las estadísticas en sí misma usa un Contador Dict:
import collections
def _counts(data):
# Generate a table of sorted (value, frequency) pairs.
table = collections.Counter(iter(data)).most_common()
if not table:
return table
# Extract the values with the highest frequency.
maxfreq = table[0][1]
for i in range(1, len(table)):
if table[i][1] != maxfreq:
table = table[:i]
break
return table
def mode(data):
"""Return the most common data point from discrete or nominal data.
``mode`` assumes discrete data, and returns a single value. This is the
standard treatment of the mode as commonly taught in schools:
>>> mode([1, 1, 2, 3, 3, 3, 3, 4])
3
This also works with nominal (non-numeric) data:
>>> mode(["red", "blue", "blue", "red", "green", "red", "red"])
''red''
If there is not exactly one most common value, ``mode`` will raise
StatisticsError.
"""
# Generate a table of sorted (value, frequency) pairs.
table = _counts(data)
if len(table) == 1:
return table[0][0]
elif table:
raise StatisticsError(
''no unique mode; found %d equally common values'' % len(table)
)
else:
raise StatisticsError(''no mode for empty data'')
Otra forma de usar un contador y atrapar una lista vacía:
def majority(l):
cn = Counter(l).most_common(2)
return 0 if len(cn) > 1 and cn[0][1] == cn[1][1] else next(iter(cn),[0])[0]
from collections import Counter
def find_majority_vote(votes):
counter = Counter(votes)
most_common = counter.most_common(2)
if len(most_common)==2:
return 0 if most_common[0][1] == most_common[1][1] else most_common[0][0]
else:
return most_common[0][0]
Esto funciona con cualquier número de candidatos. Si hay un empate entre dos candidatos, devuelve cero, de lo contrario, devuelve el candidato con la mayoría de los votos.
from collections import Counter
x = [-1, -1, 0, 0, 0, 0]
counts = list((Counter(x).most_common())) ## Array in descending order by votes
if len(counts)>1 and (counts[0][1] == counts[1][1]): ## Comparing top two candidates
print 0
else:
print counts[0][0]
Comparamos solo dos candidatos porque si hay un empate entre dos candidatos debería devolver 0 y no depende del tercer valor candidato
Un enfoque muy simple.
a = [-1, -1, -1, -1, 0] # Example
count = {}
for i in a:
if i not in count:
count[i] = 1
else:
count[i] += 1
m_count = max(count.values())
for key in count:
if count[key] == m_count:
print key
En el ejemplo anterior, la salida será -1, sin embargo, si hay un empate, ambas claves se imprimirán.
Un enfoque obvio es hacer un contador y actualizarlo de acuerdo con la lista de datos x
. Luego puede obtener la lista de números (de -1, 0, 1) que son los más frecuentes. Si hay 1 de esos números, esto es lo que desea, de lo contrario, elija 0 (como lo solicitó).
counter = {-1: 0, 0: 0, 1: 0}
for number in x:
counter[number] += 1
best_values = [i for i in (-1, 0, 1) if counter[i] == max(counter.values())]
if len(best_values) == 1:
majority = best_values[0]
else:
majority = 0
Puede contar las ocurrencias de 0 y probar si son mayoría.
>>> x = [1, 1, 0, 0, 0]
>>> if sum(x) == 0 or x.count(0) >= len(x) / 2.0:
... majority = 0
... else:
... majority = -1 if (sum(x) < 0) else 1
... majority
0