python 尝试在列表中查找第二个最大值时出错

r9f1avp5  于 2023-11-16  发布在  Python
关注(0)|答案(6)|浏览(89)

我正在尝试编写代码来查找列表的第二个最大值。
我是这样试的:

arr = map(int, input().split())
lista = list(arr)
max_value = lista[0]
run = lista[0]
for i in lista:
    if max_value < i:
        max_value = i
for j in lista:
    if run < j and run < max_value:
        run = j
print(run)

字符串
第二个最大值和最大值是一样的,我的程序中有什么错误?

omvjsjqw

omvjsjqw1#

问题

最低还款额

run = lista[0]
    ...
    if run < j and run < max_value:

字符串

v
    run = min(lista)
    ...
                   v
    if run < j and j < max_value:

如何找到问题

1.简化代码

理解而不是Map列表构造函数继承

我们可以通过使用一个理解而不是一系列的map和list构造函数来减少firsts行的样板:

arr = map(int, input().split())
lista = list(arr)


变成:

lista = [int(n) for n in input().split()]

向Python询问最大值,不要自己动手

你的下一个逻辑块是在这里找到列表的最大值。你不需要自己写这个代码,你可以问Python。这将降低你的代码的复杂性,使问题/bug更容易发现。

max_value = lista[0]
for i in lista:
    if max_value < i:
        max_value = i


变成:

max_value = max(lista)

重命名变量

为了帮助我们的大脑理解发生了什么,让我们来澄清变量的名称:

lista = [int(n) for n in input().split()]
max_value = max(lista)
run = lista[0]
for j in lista:
    if run < j and run < max_value:
        run = j
print(run)


变成:

user_input = [int(n) for n in input().split()]
max_value = max(user_input)

second_max = user_input[0]
for current_value in user_input:
    if second_max < current_value and second_max < max_value:
        second_max = current_value
        
print(second_max)

2.发现问题

现在,代码更小,更容易理解,出错的地方也更少。如果有错误,我们不必查看很多地方。
出了什么问题?second_max应该是第二个最大值,但实际上不是。是什么导致了这一点?previous_value的更新不应该发生。
所以这就是问题可能发生的地方。

if second_max < current_value and second_max < max_value:
        second_max = current_value


归因正确的,条件应该是错误的。
这似乎是正确的second_max < current_value,因为我们希望仅在second_max低于current_value(这意味着current可能是second_max的真实值或等于max_value)时才进行更新。因此,我们需要另一个条件:current_value不应是max_value,否则,second_max可能被设置为max_value
然后,我们看第二个条件:second_max < max_value,这是我们的错误。
让我们修正这个条件,因为current_value应该小于max_value。此外,如果第一个值是最大值,则需要将second_max的初始值设置为最小值。

user_input = [int(n) for n in input().split()]
max_value = max(user_input)

second_max = min(user_input)
for current_value in user_input:
    if second_max < current_value and current_value < max_value:
        second_max = current_value

print(second_max)  # 55


完了

替代方法:使用集合、排序和索引

如果您想要清单中的第二个最大值,排序已删除重复的清单并打印清单索引1处的元素(例如第二个元素)会比较容易。

逐步示例

without_duplicates = {int(n) for n in input().split()}
ordered_without_duplicates = sorted(without_duplicates, reverse=True)
print(ordered_without_duplicates[1])

单线示例

print(sorted({int(n) for n in input().split()}, reverse=True)[1])

用堆

print(heapq.nlargest(2, {int(n) for n in input().split()})[1])

hm2xizp9

hm2xizp92#

第二个循环中的测试是不正确的,使用这个:

arr = map(int, input().split())
lista = list(arr)
max_value = lista[0]
run = lista[0]
for i in lista:
    if max_value < i:
        max_value = i
for j in lista:
    if run<j and j!=max_value:
        run = j
print(run)

字符串
检查值(j)不应等于max_value

xtupzzrd

xtupzzrd3#

有趣的是,与其他common ways方法相比,您的方法(具有逻辑校正)非常快。在下面的基准测试中,它是f1
这是一个在线基准。
如果你想在自己的电脑上试试,代码是:

import random 
import time 

def f1(lista):
    max1,max2 = [lista[0]]*2
    for i in lista:
        if max1 < i:
            max1 = i
            
    for j in lista:
        if max2<j and j!=max1:
            max2 = j
    return max1,max2

def f2(lista):
    max1=max(lista)
    return max1,max(set(lista)-{max1})

def f3(lista):
    return tuple(sorted(set(lista))[-2:][::-1])

def f4(lista):
    max1 = max(lista)
    max2 = max(lista, key=lambda x: min(lista)-1 if (x == max1) else x)
    return max1,max2 

def f5(lista):
    max1=max(lista)
    max2=max(x for x in lista if x < max1)
    return max1,max2 

def f6(lista):
    import heapq
    heap = [(-x, x) for x in lista]
    heapq.heapify(heap)
    _,max1=heapq.heappop(heap)
    _,max2=heapq.heappop(heap)
    return max1,max2 

def f7(lista):
    max1 = max(lista[0], lista[1]) 
    max2 = min(lista[0], lista[1]) 
    n = len(lista)
    for i in range(2,n): 
        if lista[i] > max1: 
            max2 = max1
            max1 = lista[i] 
        elif lista[i] > max2 and max1 != lista[i]: 
            max2 = lista[i]
        elif max1 == max2 and max2 != lista[i]:
                max2 = lista[i]
                
    return max1,max2      

def f8(lista):
    max1=max2=lista[0]
    for e in lista:
        if e > max1:
            max2=max1
            max1=e
        elif e > max2:
            max2=e
    return max1,max2       

def cmpthese(funcs, args=(), cnt=1000, rate=True, micro=True):
    """Generate a Perl style function benchmark"""                   
    def pprint_table(table):
        """Perl style table output"""
        def format_field(field, fmt='{:,.0f}'):
            if type(field) is str: return field
            if type(field) is tuple: return field[1].format(field[0])
            return fmt.format(field)     
        
        def get_max_col_w(table, index):
            return max([len(format_field(row[index])) for row in table])         
        
        col_paddings=[get_max_col_w(table, i) for i in range(len(table[0]))]
        for i,row in enumerate(table):
            # left col
            row_tab=[row[0].ljust(col_paddings[0])]
            # rest of the cols
            row_tab+=[format_field(row[j]).rjust(col_paddings[j]) for j in range(1,len(row))]
            print(' '.join(row_tab))                
            
    results={}
    for i in range(cnt):
        for f in funcs:
            start=time.perf_counter_ns()
            f(*args)
            stop=time.perf_counter_ns()
            results.setdefault(f.__name__, []).append(stop-start)
    results={k:float(sum(v))/len(v) for k,v in results.items()}     
    fastest=sorted(results,key=results.get, reverse=True)
    table=[['']]
    if rate: table[0].append('rate/sec')
    if micro: table[0].append('\u03bcsec/pass')
    table[0].extend(fastest)
    for e in fastest:
        tmp=[e]
        if rate:
            tmp.append('{:,}'.format(int(round(float(cnt)*1000000.0/results[e]))))
            
        if micro:
            tmp.append('{:,.1f}'.format(results[e]/float(cnt)))
            
        for x in fastest:
            if x==e: tmp.append('--')
            else: tmp.append('{:.1%}'.format((results[x]-results[e])/results[e]))
        table.append(tmp) 
        
    pprint_table(table)                    
    
if __name__=='__main__':
    lista=[random.randint(-1e6,1e6) for _ in range(100000)]
    funcs=[f1,f2,f3,f4,f5,f6,f7,f8]
    for f in funcs: print(f'{f.__name__}: {f(lista)}')
    cmpthese(funcs, [lista])

字符串
在最近的Mac上,这将打印:

f1: (999991, 999978)
f2: (999991, 999978)
f3: (999991, 999978)
f4: (999991, 999978)
f5: (999991, 999978)
f6: (999991, 999978)
f7: (999991, 999978)
f8: (999991, 999978)
   rate/sec μsec/pass     f3     f6     f2     f4     f5     f7     f1     f8
f3      104   9,656.6     --  -3.1% -11.4% -45.9% -61.6% -71.2% -82.9% -87.3%
f6      107   9,358.3   3.2%     --  -8.6% -44.1% -60.3% -70.3% -82.3% -86.9%
f2      117   8,557.1  12.8%   9.4%     -- -38.9% -56.6% -67.5% -80.7% -85.7%
f4      191   5,227.9  84.7%  79.0%  63.7%     -- -29.0% -46.8% -68.3% -76.5%
f5      269   3,712.2 160.1% 152.1% 130.5%  40.8%     -- -25.1% -55.4% -66.9%
f7      360   2,779.1 247.5% 236.7% 207.9%  88.1%  33.6%     -- -40.4% -55.9%
f1      604   1,655.3 483.4% 465.3% 416.9% 215.8% 124.3%  67.9%     -- -25.9%
f8      815   1,226.9 687.1% 662.8% 597.5% 326.1% 202.6% 126.5%  34.9%     --

q43xntqr

q43xntqr4#

我会这样写代码:

from heapq import nlargest
from typing import List

def second_largest(values: List[int]) -> int:
    result = nlargest(2, set(values))
    return result[1]

字符串
将函数拆分后,代码更易于测试。调用者类似于海报的代码如下所示:

def second_largest_helper(value_str: str) -> int:
    return second_largest(map(int, value_str.split()))


如果传入的列表中只有一个唯一值或没有值,则代码将引发IndexError异常。
下面是我测试的简单数据:

if __name__ == '__main__':
    test_data = [
        ([2, 2, 3, 5, 4, 6, 5, 3, 7], 6),
        ([2, 2, 3, 5, 4, 6, 5, 3], 5),
        ([2, 2, 3, 5, 4, 5, 3], 4),
        ([2, 2, 3, 4, 5, 3], 4),
        ([2, 2, 3, 4, 3], 3),
        ([2, 2, 3, 3], 2),
        ([2, 2, 3], 2),
    ]
    for data, expected in test_data:
        print(f"{data = } {expected = }")
        assert second_largest(data) == expected


2023-11-14
你可以像这样为下面的基准测试代码编写代码:

def second_largest(values: List[int]) -> int:
    return nlargest(2, set(values))


或者像这样的数据集有几个重复:

def second_largest(values: List[int]) -> int:
    return nlargest(2, values)


第二个实现是目前为止最快的替代方案,根据基准测试代码,比f8快66%。

t30tvxxf

t30tvxxf5#

def second_max(arr):
    first=second=0
    for i in arr:
        if i> first:
            second=first
            first=i
        elif i> second:
            second=i
    return second

字符串

voj3qocg

voj3qocg6#

答案无法解决列表以最大值开始的异常。要解决它,

lista = [int(n) for n in input().split()]
max_value = max(lista)
for a in lista:
    if a != max_value:
        run = a
for j in lista:
    if run<j and j!=max_value:
        run = j
print(run)

字符串
在第二个for中,j!=max_valuej<max_value都可以工作。

相关问题