我正在做一个练习如下:
# B. front_x
# Given a list of strings, return a list with the strings
# in sorted order, except group all the strings that begin with 'x' first.
# e.g. ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] yields
# ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
# Hint: this can be done by making 2 lists and sorting each of them
# before combining them.
样本解决方案:
def front_x(words):
listX = []
listO = []
for w in words:
if w.startswith('x'):
listX.append(w)
else:
listO.append(w)
listX.sort()
listO.sort()
return listX + listO
我的解决方案:
def front_x(words):
listX = []
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w)
listX.sort()
words.sort()
return listX + words
当我测试我的解决方案时,结果有点奇怪。以下是我的解决方案的源代码:http://dl.dropbox.com/u/559353/list1.py。你可能想尝试一下。
答案 0 :(得分:3)
问题是你循环遍历列表并从中删除元素(修改它):
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w)
示例:
>>> a = range(5)
>>> for i in a:
... a.remove(i)
...
>>> a
[1, 3]
此代码的工作原理如下:
1
因为我们之前删除了0
,因此1
成为新的第一个元素。因此,下一个元素为2
,并且会跳过1
。3
和4
相同。答案 1 :(得分:1)
两个主要区别:
words
。因此,函数front_x
的调用者将在执行函数后看到words
被修改。除非明确预期,否则此行为最好避免。想象一下,您的程序正在使用words
执行其他操作。保留sample solution
中的两个列表是一种更好的方法。答案 2 :(得分:0)
更改您正在迭代的列表会导致未定义的行为。这就是示例解决方案创建两个新列表而不是从源列表中删除的原因。
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w) # Problem here!
有关此问题的讨论,请参阅this question。它基本上归结为列出遍历列表索引的迭代器,而不返回并检查修改(这将是昂贵的!)。
如果要避免创建第二个列表,则必须执行两次迭代。一个用于迭代words
以创建listX
而另一个用于迭代listX
从words
删除。
答案 3 :(得分:0)
该提示具有误导性和不必要性,您无需单独排序和组合两个列表即可完成此操作:
>>> items = ['mix', 'xyz', 'apple', 'xanadu', 'aardvark']
>>> sorted(items, key=lambda item: (item[0]!='x', item))
['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
内置的sorted()函数接受一个选项键参数,告诉它要排序的内容。在这种情况下,您希望为原始列表的每个元素创建一个类似(False,'xanadu')或(True,'apple')的元组,您可以使用lambda。