为什么我的代码无法获得预期的回报?

时间:2012-08-14 21:57:15

标签: python

grade=['Ben Anderson',95,90,100,-1,'Mary Johnson',75,78,79,-5,'Michael Walter',80,68,0]   

def convert_grades(lst):
    a = []
    b = []
    for i in lst:
        if isinstance(i,str):
            c = 0
            while lst[c] < 0 or lst[c] == []:
                a = a + lst[c]
                c = c + 1
            b = b + a   
    return b

我希望它以

的形式返回
[['Ben Anderson',95,90,100],['Mary Johnson',75,78,79],['Michael Walter',80,68,0]]

但它返回[]

我不知道发生了什么事。需要帮助。

6 个答案:

答案 0 :(得分:5)

具有相同形式的输入和输出的建议:

def convert_grades(lst):
    out = []
    for element in grade:
        if isinstance(element, str):
            buf = []         # re-initializes 'buf' everytime there is a string
            out.append(buf)
        buf.append(element)
    return out

前代码的非pythonicity的三个主要症状:

  1. 使用算术运算符,熟悉python习语的人会使用类型方法(在这种情况下为list.append);
  2. 列表中的输入,其中明显的数据类型应该是字典(尽管并不总是可以控制如何获取数据);
  3. 而且,最严重的症状是,OUTPUT是一个列表,当它实际上是在乞讨字典时。
  4. 所以,这是一种更加pythonic的方式,返回字典而不是列表:

    def convert_grades(lst):
        out = {}
        for element in grade:
            if isinstance(element, str):
                key = element
                out[key] = []
            else:
                out[key].append(element)   ## mind that this would raise an error if first element in lst is not string
        return out
    
    print convert_grades(grade)
    

    希望这有帮助!

答案 1 :(得分:3)

我认为itertools.groupby()可能非常适用于此:

from itertools import groupby

def convert_grades(lst):
    key = lambda x: isinstance(x, int) and x < 0
    return [list(g) for k, g in groupby(lst, key) if not k]

结果:

>>> convert_grades(['Ben Anderson',95,90,100,-1,'Mary Johnson',75,78,79,-5,'Michael Walter',80,68,0])
[['Ben Anderson', 95, 90, 100], ['Mary Johnson', 75, 78, 79], ['Michael Walter', 80, 68, 0]]

这可以通过创建一个函数key来实现,该函数在列表条目作为分隔符时返回True,而在不应该作为分隔符时返回False。通过在itertools.groupby()中使用此函数,我们可以创建所有组,然后我们只需要从生成的可迭代中过滤掉所有分隔符值。

答案 2 :(得分:1)

尝试这样的事情:

grade=['Ben Anderson',95,90,100,-1,'Mary Johnson',75,78,79,-5,'Michael Walter',80,68,0]

def convert_grades(lst):
    a = []
    for i in lst:
        if isinstance(i,str):
            a.append([])           #if a string is found than append a [] to a 
            a[-1].append(i)         #append i to the last element of a   
        elif i>=0:
            a[-1].append(i)        #if not string then just append i to the last element of a       
    return a        

print(convert_grades(grade))

<强>输出

[['Ben Anderson', 95, 90, 100], ['Mary Johnson', 75, 78, 79], ['Michael Walter', 80, 68, 0]]

答案 3 :(得分:1)

又一个答案(虽然我比{3}更喜欢我)和一些评论(只是建议):

#!/usr/bin/env python

def convert_grades1(lst):
    a = []
    b = []

    index = 0
    while index < len(lst):
        if isinstance(lst[index], str):
            b.append(lst[index])
            index = index + 1
            try:
                while isinstance(lst[index], int):
                    if lst[index] > 0:
                        b.append(lst[index])
                    index += 1
            except IndexError:
                print "We're done"
            finally:
                a.append(b)
                b = []
    return a

if __name__ == "__main__":
    grade=['Ben Anderson',95,90,100,-1,'Mary Johnson',75,78,79,-5,'Michael Walter',80,68,0]
    print convert_grades1(grade)

1)

如果你用“行走”列表(或解析文件或其他......),而循环则认为你是否真的需要在嵌套循环中从头开始重新开始行走。在您的代码中:

for i in lst:
    if isinstance(i,str):
        c = 0
        while lst[c] < 0 or lst[c] == []:

你开始重新遍历整个列表(在进入之前你做c=0),即使你可能已经在之前的中处理了一大块 “通行证”。我猜你在考虑将i作为索引(不是,i获取列表中项目的值)。对于索引,请使用:for i in range(0, len(lst))for i, item in enumerate(lst)

2)

 c = 0
 while lst[c] < 0 or lst[c] == []:

在那里,lst[c]指向列表中的第一个项目(意思是字符串'Ben Anderson'),它既不小于0也不是空列表,因此while循环是永远不会被执行。

3)

它通常被认为是“pythonic”,让你的代码遵循“更好地对不起比安全”的想法,所以你可以(在你的例子中)尝试解析int而不是if isinstance(i,str)如果它失败了......那么你可以假设它是一个字符串。

if isinstance(element, str):
    #do stuff for string
else:
    #do other stuff (for int)

可以是等效的(在您的情况下):

try:
  int(element)
  #do other stuff (for int)
except ValueError: 
  #do stuff for string

请注意,因为int("5")不会抛出任何异常(即使"5"实际上是str)。它会为您提供int,其值为5

4)

如果您是初学者,print是您的朋友;)

答案 4 :(得分:1)

为了完成,您可以将此结构[str, int, int, str, int]视为堆栈,并从左侧弹出到您希望的结构中:

grades=['Ben Anderson',95,90,100,-1,'Mary Johnson',75,78,79,-5,'Michael Walter',80,68,0]
converted_list=[]
while grades:
    temp=[grades.pop(0)]
    while grades and isinstance(grades[0],int):
        temp.append(grades.pop(0))

    converted_list.append(temp)

print converted_list     

打印:

[['Ben Anderson', 95, 90, 100, -1], ['Mary Johnson', 75, 78, 79, -5], ['Michael Walter', 80, 68, 0]]

您可以使用相同的方法创建字典,这似乎是一个更好的数据结构:

d={}
while grades:
    name=grades.pop(0)
    d[name]=[]
    while grades and isinstance(grades[0],int):
        d[name].append(grades.pop(0))

print d     

打印:

{'Mary Johnson': [75, 78, 79, -5], 'Michael Walter': [80, 68, 0], 'Ben Anderson': [95, 90, 100, -1]}

虽然这有效,但是恕我直言,F.J的回答是最“邪恶的”

答案 5 :(得分:0)

如果你想要理解,这可行:

grades=['Ben Anderson',95,90,100,-1,'Mary Johnson',75,78,79,-5,'Michael Walter',80,68,0]
eyes=[i for i, x in enumerate(grades) 
    if isinstance(x,str)]+[len(grades)+1]         # index of the strings
LofSL=[(i,j) for i,j in zip(eyes[:-1],eyes[1:])]  # slices for each list
LoL=[grades[t[0]:t[1]] for t in LofSL]            # your list of lists

或者,如果你想要一本字典:

DofL={grades[t[0]]:grades[t[0]+1:t[1]] for t in LofSL}