将列表中的所有最小值更新为下一个最小值

时间:2015-10-03 07:41:55

标签: python python-2.7 python-3.x

如何在python列表中增加数字,以便仅更新该列表中的当前最小值。 例如:

a = [15,15,14,12,10,10,10]

我有一个号码x=12 我需要最优地将它分配给这个数组,使得最大值最小,即首先我给每个10,2,2,2,2,2,2到任何3 12。我的最终列表如下所示:

a = [15,15,14,14,14,14,12]

3 个答案:

答案 0 :(得分:1)

要将列表中的所有最小值更新为下一个最小值,您可以使用以下方法。

首先使用Python的min函数确定最小值。然后通过迭代每个值来计算第二个最小值。然后可以使用列表推导将任何小于第二个最小值的值更新为第二个最小值:

import sys

a = [15,15,14,12,10,10,10]
smallest = min(a)
second_smallest = sys.maxint        # Largest possible allowed integer

for x in a:
    if smallest < x < second_smallest:
        second_smallest = x

a[:] = [second_smallest if x < second_smallest else x for x in a]

print a

显示以下内容:

[15, 15, 14, 12, 12, 12, 12]

答案 1 :(得分:0)

我将把我以前的解决方案留给“历史兴趣”。这是很多更好的解决方案。代码不仅显着缩短,而且在计算和更新列表方面效率更高。

#!/usr/bin/env python

''' Increment the minimum items of seq until sum(seq) has increased by n

    From http://stackoverflow.com/q/32920173/4014959

    Written by PM 2Ring 2015.10.04
'''

def increment_minimum(seq, n):
    ''' Increment the minimum items of seq until sum(seq) has increased by n
        seq must be sorted ascending.
    '''
    total = n
    for i, val in enumerate(seq):
        if i * val > total:
            break
        total += val
    else:
        i = len(seq)
        #print '*',

    val, rem = divmod(total, i)
    seq[:i] = [val] * (i - rem) + [val + 1] * rem


# Test
source_list = [10, 10, 10, 12, 14, 15, 15, 18]
s = sum(source_list)
print 'org %s %d' % (source_list, s)

for n in range(0, 50):
    a = source_list[:]
    increment_minimum(a, n)
    newsum = sum(a)
    print '%2d: %s %d %d' % (n, a, newsum, newsum - (s + n))

<强>输出

org [10, 10, 10, 12, 14, 15, 15, 18] 104
 0: [10, 10, 10, 12, 14, 15, 15, 18] 104 0
 1: [10, 10, 11, 12, 14, 15, 15, 18] 105 0
 2: [10, 11, 11, 12, 14, 15, 15, 18] 106 0
 3: [11, 11, 11, 12, 14, 15, 15, 18] 107 0
 4: [11, 11, 12, 12, 14, 15, 15, 18] 108 0
 5: [11, 12, 12, 12, 14, 15, 15, 18] 109 0
 6: [12, 12, 12, 12, 14, 15, 15, 18] 110 0
 7: [12, 12, 12, 13, 14, 15, 15, 18] 111 0
 8: [12, 12, 13, 13, 14, 15, 15, 18] 112 0
 9: [12, 13, 13, 13, 14, 15, 15, 18] 113 0
10: [13, 13, 13, 13, 14, 15, 15, 18] 114 0
11: [13, 13, 13, 14, 14, 15, 15, 18] 115 0
12: [13, 13, 14, 14, 14, 15, 15, 18] 116 0
13: [13, 14, 14, 14, 14, 15, 15, 18] 117 0
14: [14, 14, 14, 14, 14, 15, 15, 18] 118 0
15: [14, 14, 14, 14, 15, 15, 15, 18] 119 0
16: [14, 14, 14, 15, 15, 15, 15, 18] 120 0
17: [14, 14, 15, 15, 15, 15, 15, 18] 121 0
18: [14, 15, 15, 15, 15, 15, 15, 18] 122 0
19: [15, 15, 15, 15, 15, 15, 15, 18] 123 0
20: [15, 15, 15, 15, 15, 15, 16, 18] 124 0
21: [15, 15, 15, 15, 15, 16, 16, 18] 125 0
22: [15, 15, 15, 15, 16, 16, 16, 18] 126 0
23: [15, 15, 15, 16, 16, 16, 16, 18] 127 0
24: [15, 15, 16, 16, 16, 16, 16, 18] 128 0
25: [15, 16, 16, 16, 16, 16, 16, 18] 129 0
26: [16, 16, 16, 16, 16, 16, 16, 18] 130 0
27: [16, 16, 16, 16, 16, 16, 17, 18] 131 0
28: [16, 16, 16, 16, 16, 17, 17, 18] 132 0
29: [16, 16, 16, 16, 17, 17, 17, 18] 133 0
30: [16, 16, 16, 17, 17, 17, 17, 18] 134 0
31: [16, 16, 17, 17, 17, 17, 17, 18] 135 0
32: [16, 17, 17, 17, 17, 17, 17, 18] 136 0
33: [17, 17, 17, 17, 17, 17, 17, 18] 137 0
34: [17, 17, 17, 17, 17, 17, 18, 18] 138 0
35: [17, 17, 17, 17, 17, 18, 18, 18] 139 0
36: [17, 17, 17, 17, 18, 18, 18, 18] 140 0
37: [17, 17, 17, 18, 18, 18, 18, 18] 141 0
38: [17, 17, 18, 18, 18, 18, 18, 18] 142 0
39: [17, 18, 18, 18, 18, 18, 18, 18] 143 0
40: [18, 18, 18, 18, 18, 18, 18, 18] 144 0
41: [18, 18, 18, 18, 18, 18, 18, 19] 145 0
42: [18, 18, 18, 18, 18, 18, 19, 19] 146 0
43: [18, 18, 18, 18, 18, 19, 19, 19] 147 0
44: [18, 18, 18, 18, 19, 19, 19, 19] 148 0
45: [18, 18, 18, 19, 19, 19, 19, 19] 149 0
46: [18, 18, 19, 19, 19, 19, 19, 19] 150 0
47: [18, 19, 19, 19, 19, 19, 19, 19] 151 0
48: [19, 19, 19, 19, 19, 19, 19, 19] 152 0
49: [19, 19, 19, 19, 19, 19, 19, 20] 153 0

这是一种简单的方法,可以将列表的最小项目增加1,直到列表总和增加了所需的数量。

def increment_minimum(seq, n):
    ''' Increment the minimum item of seq n times '''
    for _ in range(n):
        m = min(seq)
        i = seq.index(m)
        seq[i] += 1
        print seq

a = [15, 15, 14, 12, 10, 10, 10]
print a, sum(a)

increment_minimum(a, 12)
print a, sum(a)

<强>输出

[15, 15, 14, 12, 10, 10, 10] 86
[15, 15, 14, 12, 11, 10, 10]
[15, 15, 14, 12, 11, 11, 10]
[15, 15, 14, 12, 11, 11, 11]
[15, 15, 14, 12, 12, 11, 11]
[15, 15, 14, 12, 12, 12, 11]
[15, 15, 14, 12, 12, 12, 12]
[15, 15, 14, 13, 12, 12, 12]
[15, 15, 14, 13, 13, 12, 12]
[15, 15, 14, 13, 13, 13, 12]
[15, 15, 14, 13, 13, 13, 13]
[15, 15, 14, 14, 13, 13, 13]
[15, 15, 14, 14, 14, 13, 13]
[15, 15, 14, 14, 14, 13, 13] 98

即使seq未排序,此功能也能正常执行,并且不会影响seq中项目的排序。效率不高,但seq很短且n很小时可能就足够了。

更有效的方法是使用heap queue

def increment_minimum(seq, n):
    ''' Increment the minimum item of seq n times '''
    #Build heap from seq
    heap = seq[:]
    heapq.heapify(heap)

    for _ in range(n):
        #Increment the smallest item on the heap
        m = heapq.heappop(heap)
        heapq.heappush(heap, m + 1)

    #Copy heap items back to seq
    for i in range(len(seq)):
        seq[-1-i] = heapq.heappop(heap)

此版本还处理未排序的输入,但由于堆队列的工作方式,更新的列表将始终排序。

seq包含许多项时,此函数比以前的版本更有效,但如果您打算在同一列表上多次调用它,那么最好是在外部维护堆而不是重建它在每个电话的功能。但是,当n很大时,此版本仍然不是特别有效。为了更有效地处理大n,我怀疑itertools.groupby会很有用。

这是一个应该更高效的版本,特别是如果n足够大,可以将列表中的所有项目增加为&gt; =当前最大值。

#!/usr/bin/env python

''' Increment the minimum items of seq until sum(seq) has increased by n

    From http://stackoverflow.com/q/32920173/4014959

    Written by PM 2Ring 2015.10.03
'''

from itertools import groupby

def increment_minimum(seq, n):
    ''' Increment the minimum items of seq
        until sum(seq) has increased by n

        seq must be sorted ascending.
    '''
    #Check if n is large enough to make all items 
    # >= the current max.
    newsum = n + sum(seq)
    seqlen = len(seq)
    if newsum >= seq[-1] * seqlen:
        v, r = divmod(newsum, seqlen)
        seq[:] = [v] * (seqlen - r) + [v+1] * r
        return

    #Otherwise, successively increment the groups of smallest items
    #to the value of the next smallest items

    #Split items into groups of equal value
    a = [(len(list(g)), v) for v, g in groupby(seq)]
    k = 0
    for i in range(len(a) - 1):
        #Get the cumulative number of group items
        k += a[i][0]

        #Get the difference in value between this group & the next smallest 
        v = a[i+1][1] - a[i][1]

        #Increment the k smallest items by (at most) v
        for j in range(k-1, -1, -1):
            if v <= n:
                seq[j] += v
                n -= v
            else:
                seq[j] += n
                return


# Test
source_list = [10, 10, 10, 12, 14, 15, 15, 16]
s = sum(source_list)

for n in range(30):
    a = source_list[:]
    increment_minimum(a, n)
    print '%2d: %s %s' % (n, a, sum(a) == s + n)

<强>输出

 0: [10, 10, 10, 12, 14, 15, 15, 16] True
 1: [10, 10, 11, 12, 14, 15, 15, 16] True
 2: [10, 10, 12, 12, 14, 15, 15, 16] True
 3: [10, 11, 12, 12, 14, 15, 15, 16] True
 4: [10, 12, 12, 12, 14, 15, 15, 16] True
 5: [11, 12, 12, 12, 14, 15, 15, 16] True
 6: [12, 12, 12, 12, 14, 15, 15, 16] True
 7: [12, 12, 12, 13, 14, 15, 15, 16] True
 8: [12, 12, 12, 14, 14, 15, 15, 16] True
 9: [12, 12, 13, 14, 14, 15, 15, 16] True
10: [12, 12, 14, 14, 14, 15, 15, 16] True
11: [12, 13, 14, 14, 14, 15, 15, 16] True
12: [12, 14, 14, 14, 14, 15, 15, 16] True
13: [13, 14, 14, 14, 14, 15, 15, 16] True
14: [14, 14, 14, 14, 14, 15, 15, 16] True
15: [14, 14, 14, 14, 15, 15, 15, 16] True
16: [14, 14, 14, 15, 15, 15, 15, 16] True
17: [14, 14, 15, 15, 15, 15, 15, 16] True
18: [14, 15, 15, 15, 15, 15, 15, 16] True
19: [15, 15, 15, 15, 15, 15, 15, 16] True
20: [15, 15, 15, 15, 15, 15, 16, 16] True
21: [15, 15, 15, 15, 15, 16, 16, 16] True
22: [15, 15, 15, 15, 16, 16, 16, 16] True
23: [15, 15, 15, 16, 16, 16, 16, 16] True
24: [15, 15, 16, 16, 16, 16, 16, 16] True
25: [15, 16, 16, 16, 16, 16, 16, 16] True
26: [16, 16, 16, 16, 16, 16, 16, 16] True
27: [16, 16, 16, 16, 16, 16, 16, 17] True
28: [16, 16, 16, 16, 16, 16, 17, 17] True
29: [16, 16, 16, 16, 16, 17, 17, 17] True

答案 2 :(得分:0)

尝试:

def distribute(l, n):
    m = max(l) - 1
    for i in range(len(l)):
        if not n:
            break
        incr = min(m - l[i], n)
        if incr > 0:
            l[i] += incr
            n -= incr

a = [15, 15, 14, 12, 10, 10, 10]
distribute(a, 12)
print a