如何在Python中修复“ IndexError:列表索引超出范围”

时间:2019-04-23 03:13:57

标签: python

这是应该,根据他们执行的任务数量(他们在输入列表中出现了多少次),以及如果有2名参赛者具有相同数量的任务,然后按时间排序(最小到最大)。

例如,给定此

["tyson 0:11", "usain 0:12", "carl 0:30", "carl 0:20", "usain 0:40", "carl 1:00", "usain 0:57"]

作为输入,应该返回以下内容:

["usain", "carl", "tyson"]

但是,在按任务排序之后,我似乎无法弄清楚如何按时间排序。

代码:

from  more_itertools import unique_everseen

def winners(data):
    names = []
    times = []
    taskcount = []
    ndict = {}

    for i in data:
        name = i.split()[0]
        time = i.split()[1]
        numMin, numSec = time.split(':')

        nmin = int(numMin)
        nsec = int(numSec)
        total = (60 * nmin) + nsec

        names.append(name)
        times.append(total)

    index = 0
    for name in names:
        count = names.count(name)
        taskcount.append(count)

    for name in names:
        taskcount.pop(0)

    taskcount = list(unique_everseen(taskcount))

    for name in names:    
        if name not in ndict:
            ndict[name] = [taskcount[index], times[index]]
        else:
            ndict[name][1] += times[index]
        index += 1
    sortedDict = sorted(ndict.items(),reverse = True , key=lambda kv: kv[1])
    R = [t[0] for t in sortedDict]
    return R

最重要的是,每当我输入某个列表时,它看起来都可以正常工作,但当我输入其他列表时,它就爆炸了:

Traceback (most recent call last):

  File "<ipython-input-69-420jihgfedcc>", line 1, in <module>
    runfile('C:/Users/User/Folder/contestWinner.py', wdir='C:/Users/User/Folder')

  File "C:\Users\User\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 704, in runfile
    execfile(filename, namespace)

  File "C:\Users\User\Anaconda3\lib\site-packages\spyder_kernels\customize\spydercustomize.py", line 108, in execfile
    exec(compile(f.read(), filename, 'exec'), namespace)

  File "C:/Users/User/Folder/contestWinner.py", line 42, in <module>
    print(winners(data))

  File "C:/Users/User/Folder/contestWinner.py", line 33, in winners
    ndict[name] = [taskcount[index], times[index]]

IndexError: list index out of range

反正有没有解决错误和按时间排序的方法?抱歉,如果这真的很愚蠢,我是Python的初学者。

4 个答案:

答案 0 :(得分:1)

另一个答案已解决了该问题,但我想提出一种更实用的方法:

data = ["tyson 0:11", "usain 0:12", "carl 0:30", "carl 0:20", "usain 0:40", "carl 1:00", "usain 0:57"]

from itertools import groupby
from operator import itemgetter

def process_time(t):
    minutes, seconds = map(int, t.split(':'))
    return 60 * minutes + seconds

def sort_key(pair):
    return (-len(pair[1]), min(pair[1]))

grouped = groupby(sorted(task.split() for task in data), 
                  key=itemgetter(0))

processed = {key: [process_time(time) for name, time in group] 
             for key, group in grouped}

print(processed)
print([name for name, time in sorted(processed.items(), key=sort_key)])

输出:

{'carl': [20, 30, 60], 'tyson': [11], 'usain': [12, 40, 57]}
['usain', 'carl', 'tyson']

首先,我们使用sorteditertools.groupby按第一个元素对输入数据中的每个条目进行排序和分组。这样一来,我们就可以以dict的结构化形式获取数据,其中键是名称,值是lists倍。

一路走来,我们还将表示时间的字符串处理为以秒为单位的整数。

接下来,我们要按dict的键值对它们进行排序,首先按长度的降序(因为值的长度是任务数),然后按最小时间的升序进行排序。

这是通过指定键函数sort_key来完成的,该键函数在此返回一个tuple。按键功能的作用是对输入进行排序,就像对按键应用了一样。

tuples按其第一个元素排序,然后按第二个元素排序,依此类推,直到打破所有联系或到达最后一个元素为止。在这种情况下,我们有一个2元组,其中第一个元素是输入的长度,第二个元素是最小值。

请注意,前者是负数,因为默认情况下sorted顺序排序;通过忽略长度,我们可以颠倒排序顺序。在仅对一个元素进行排序的情况下,您可以传递reverse=True,但是在这里,我们可以按不同的顺序进行两种排序。

所有这些的结果是我们执行了必要的排序才能得到答案。

答案 1 :(得分:0)

由于以下几行而出现此错误:

for name in names:
    taskcount.pop(0)

taskcount = list(unique_everseen(taskcount))

删除这些内容也会删除错误。

但是,您的代码仍不会返回您期望的顺序,因为它将更多的时间放在首位。您会在末尾或返回[('carl', [3, 110]), ('usain', [3, 109]), ('tyson', [1, 11])]时得到['carl', 'usain', 'tyson'],因为卡尔的总时间比美国长。

应该只对sortedDict = sorted(ndict.items(),reverse = True , key=lambda kv: kv[1])行进行调整,以便按时间在相反的方向上进行排序。

答案 2 :(得分:0)

 from collections import Counter

data_release = ["tyson 0:11", "usain 0:12", "carl 0:30", "carl 0:20", "usain 0:40", "carl 1:00", "usain 0:57"]


def sorted_data(data):
    temp_data = []
    for item in data:
        item = item.split()[0]
        temp_data.append(item)

    temp_dict = dict(Counter(temp_data))
    sorted_list = sorted(temp_dict.items(), key=lambda d: - d[1])

    result = []
    for temp_tuple in sorted_list:
        result.append(temp_tuple[0])

    return result


    print(sorted_data(data_release))

充分利用python集合库,问题会更加简单!

答案 3 :(得分:0)

我通过稍微修改gmds的代码解决了这个问题,所以我将接受他/她的代码。我使用了一个简单的嵌套for循环,用原始值中组合时间的列表替换了processed的每个值。谢谢gmds!

代码:

from itertools import groupby
from operator import itemgetter

def winners(data):
    def process_time(t):
        minutes, seconds = map(int, t.split(':'))
        return 60 * minutes + seconds

    def sort_key(pair):
        return (-len(pair[1]), min(pair[1]))

    grouped = groupby(sorted(task.split() for task in data), key=itemgetter(0))

    processed = {key: [process_time(time) for name, time in group]
                 for key, group in grouped}

    for name in list(processed.keys()):
        length = len(processed.get(name))
        value = []
        for i in range(length):
            value.append(sum(processed.get(name)))

        processed[name] = value

    sortedL = [name for name, time in sorted(processed.items(), key = sort_key)]
    return sortedL

if __name__ == "__main__":
    data = ["owen 2:00", "jeff 1:29", "owen 1:00", "jeff 1:30", "robert 0:21"]    
    print(winners(data))

感谢帮助人员!