Python中的for循环问题
这段代码的目的是根据self.order中的字符顺序来对self.array里的项目进行排序。这个排序的方法在前两次运行得很好,但到了第三次的时候,似乎出现了问题,for循环好像无限重复下去。到底发生了什么呢?
补充说明:我在做自己的排序函数,因为这是我Python作业的一个加分部分。
class sorting_class:
def __init__(self):
self.array = ['ca', 'bd', 'ac', 'ab'] #An array of strings
self.arrayt = []
self.globali = 0
self.globalii = 0
self.order = ['a', 'b', 'c', 'd'] #Order of characters
self.orderi = 0
self.carry = []
self.leave = []
self.sortedlist = []
def sort(self):
for arrayi in self.arrayt: #This should only loop for the number items in self.arrayt. However, the third time this is run it seems to loop indefinitely.
print ('run', arrayi) #Shows the problem
if self.order[self.orderi] == arrayi[self.globali]:
self.carry.append(arrayi)
else:
if self.globali != 0:
self.leave.append(arrayi)
def srt(self):
self.arrayt = self.array
my.sort() #First this runs the first time.
while len(self.sortedlist) != len(self.array):
if len(self.carry) == 1:
self.sortedlist.append(self.carry)
self.arrayt = self.leave
self.leave = []
self.carry = []
self.globali = 1
self.orderi = 0
my.sort()
elif len(self.carry) == 0:
if len(self.leave) != 0: #Because nothing matches 'aa' during the second iteration, this code runs the third time"
self.arrayt = self.leave
self.globali = 1
self.orderi += 1
my.sort()
else:
self.arrayt = self.array
self.globalii += 1
self.orderi = self.globalii
self.globali = 0
my.sort()
self.orderi = 0
else: #This is what runs the second time.
self.arrayt = self.carry
self.carry = []
self.globali += 1
my.sort()
my = sorting_class()
my.srt()
3 个回答
你有一行代码 self.arrayt = self.leave
,这意味着 arrayt
和 leave
指向的是同一个数组(这不是内容的复制!),然后在循环 for arrayi in self.arrayt:
中,你执行了 self.leave.append(arrayi)
,这会让 self.leave
的长度增加,而 self.leave
其实就是你正在循环的 self.arrayt
的另一个名字。对正在循环的列表进行添加操作,很容易导致无限循环。
这只是代码混乱的一个表现。我建议你使用内置的 sort
方法来进行排序,把精力放在定义合适的 key=
提取函数上,这样可以让你想要的排序方式实现——这会更有效率。
在你循环的第三次运行时,你正在往正在遍历的列表中添加新元素,所以你永远无法跳出这个循环:
self.arrayt = self.leave
- 这个赋值操作导致 self.leave.append(arrayi)
会把元素添加到 self.arrayt
所指向的列表中。
一般来说,你可以考虑创建列表的副本,而不是让不同的变量或成员指向同一个列表。
Alex提到的这个关键提取器其实很简单,可以用一个lambda函数来实现。
>>> array = ['ca', 'bd', 'ac', 'ab']
>>> order = ['a', 'b', 'c', 'd']
>>> sorted(array, key=lambda v:map(order.index,v))
['ab', 'ac', 'bd', 'ca']
>>> order = ['b', 'a', 'c', 'd']
>>> sorted(array, key=lambda v:map(order.index,v))
['bd', 'ab', 'ac', 'ca']
>>> order = ['d', 'c', 'b', 'a']
>>> sorted(array, key=lambda v:map(order.index,v))
['ca', 'bd', 'ac', 'ab']
我们来看看这是怎么工作的:
map
会对v
中的每个元素调用order.index
这个方法,然后把返回的结果用来创建一个列表。
v
会是array
中的某个元素。
>>> order = ['a', 'b', 'c', 'd']
>>> map(order.index,array[0])
[2, 0]
>>> map(order.index,array[1])
[1, 3]
>>> map(order.index,array[2])
[0, 2]
>>> map(order.index,array[3])
[0, 1]
这个函数作为key=
参数提供给排序,所以实际上是对那些列表进行排序,而不是对字符串进行排序。