关于在列表中的-1s、1s和0s上查找多数票

Finding majority votes on -1s, 1s and 0s in list - python

如何找到包含-1s、1s和0s的列表的多数票?

例如,给出了以下列表:

1
x = [-1, -1, -1, -1, 0]

多数是-1,所以输出应该返回-1

另一个例子是:

1
x = [1, 1, 1, 0, 0, -1]

多数票将是1票。

当我们平局时,多数票应返回0,例如:

1
x = [1, 1, 1, -1, -1, -1]

这也应返回零:

1
x = [1, 1, 0, 0, -1, -1]

最简单的获得多数票的情况似乎是总结名单,检查它是消极的,积极的还是0。

1
2
3
4
5
6
7
8
9
>>> 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

合计后,我可以做这个检查,以获得多数票,即:

1
2
3
4
5
6
7
8
>>> 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

但正如前面提到的,它是丑陋的:Python将if-elif-else语句放在一行上,而不是放在pythonic上。

所以解决办法似乎是

1
2
3
4
5
6
7
8
>>> x = [-1, -1, 1, 1, 0]
>>> if sum(x) == 0:
...     majority = 0
... else:
...     majority = -1 if sum(x) < 0 else 1
...
>>> majority
0

编辑

但也有一些情况是,sum()不起作用,例如@Robertb's。

1
2
3
>>> x = [-1, -1, 0, 0, 0, 0]
>>> sum(x)
-2

但在这种情况下,多数票应该是0!!


我假设0票的票算作票。因此,sum不是一个合理的选择。

试试柜台:

1
2
3
4
5
6
7
8
>>> 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

因此,您可以编写如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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'


如果使用python>=3.4,则可以使用statistics.mode,在没有唯一模式时捕获StatisticsError

1
2
3
4
5
6
7
from statistics import mode, StatisticsError

def majority(l):
    try:
        return mode(l)
    except StatisticsError:
        return 0

统计信息实现本身使用计数器dict:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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')

另一种使用计数器并捕获空列表的方法:

1
2
3
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]


此解决方案基于计数发生次数和排序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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()

此外,还有一个if语句。正如评论中提到的,它没有定义发生了什么

x = [1, 1, 0, 0, -1]


您可以计算0的出现次数,并测试它们是否占多数。

1
2
3
4
5
6
7
>>> 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


一个显而易见的方法是制作一个计数器并根据数据列表x进行更新。然后你可以得到最频繁的数字列表(从-1,0,1)。如果有1个这样的数字,这就是您想要的,否则选择0(根据您的要求)。

1
2
3
4
5
6
7
8
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

一种非常简单的方法。

1
2
3
4
5
6
7
8
9
10
11
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

在上面的示例中,输出将为-1,但是,如果有领带,两个钥匙都将被打印出来。


这适用于任何数量的候选人。如果两个候选人之间有平局,则返回零,否则返回多数选票的候选人。

1
2
3
4
5
6
7
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]

我们只比较两个候选,因为如果两个候选之间有一个平局,它应该返回0,并且不依赖于第三个候选值。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 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)

我相信这适用于所有提供的测试用例。如果我做错了请告诉我。

1
2
3
4
5
6
7
8
9
10
11
12
13
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


1
2
3
4
5
from collections import Counter

result = Counter(votes).most_common(2)

result = 0 if result[0][1] == result[1][1] else result[0][0]

空的votes列表或集合基数为1的votes列表的错误处理非常简单,留给读者作为练习。


1
2
3
4
5
6
7
8
9
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]


除了内置的列表操作符和东西之外,您不需要任何东西,也不需要导入任何东西。

1
2
3
4
5
6
7
8
9
10
  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

3d行将各个投票的计数放入一个新的列表中,counts.index()显示我们找到最大投票的列表位置。

我敢说,这应该是尽可能的Python,而不是进入挖眼的一行。

upd:重写不带文本字符串的内容,如果有几个结果相等,则更新为返回0(在原始日志中没有注意到),如果只有一个投票,则添加一个if for case,例如votes=[-1]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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]))