编写类似于 reverse() 函数的 Python 代码
Writing Python code that works like the reverse() function
我想分解 reverse() 函数并将其写成代码以供练习。我最终想出了如何去做(向后遍历原始列表并附加到新的 'reversed' 列表)但想知道为什么这不起作用。
def reverse(list):
newlist = []
index = 0
while index < len(list):
newlist[index] = list[(len(list)) - 1 - index]
index = index + 1
return newlist
list = [1, 2, 3, 4, 5]
print(reverse(list))
不能为长度为 0 的列表分配任意索引。这样做会引发 IndexError。由于您是按顺序分配元素,因此您可以只进行追加而不是对索引进行分配:
newlist.append(l[(len(l)) - 1 - index])
附加修改列表并自动增加其长度。
让您的原始代码工作的另一种方法是更改 newlist
的初始化,以便它有足够的长度来支持您的索引操作:
newlist = [None for _ in range(len(l))]
我还想指出,以内置类型和函数命名事物并不是一个好主意。这样做会影响内置函数的功能。
首先不要覆盖内置函数(list
在你的情况下)第二个 newlist
有一个 len
为 0 因此不能被索引访问。
def reverse(mylist):
newlist = [0] * len(mylist)
index = 0
while index < len(mylist):
newlist[index] = mylist[(len(mylist)) - 1 - index]
index = index + 1
return newlist
mylist = [1, 2, 3, 4, 5]
print(reverse(mylist))
您可以创建一个列表,其值与输入列表的长度相同,就像这样
newlist = [0] * len(mylist)
您需要使用 list.append
。 newlist[0]
是一个有效的操作,如果列表中至少有一个元素,但 newlist
在第一次迭代中是空的。此外,list
不是变量的好名称,因为有一个 python 内置容器同名:
def reverse(lst):
newlist = []
index = 0
while index < len(lst):
newlist.append(lst[(len(list)) - 1 - index])
index += 1
return newlist
list = [1, 2, 3, 4, 5]
print(reverse(list))
在 Python 中,如果索引不在 0 和列表长度 - 1 的范围内,则不能 access/update 列表的元素。
在您的例子中,您正试图分配给 0 处的元素,但列表为空。所以,它没有索引 0。这就是它失败并显示错误的原因,
IndexError: list assignment index out of range
相反,您可以使用 append
函数,像这样
newlist.append(list[(len(list)) - 1 - index])
除此之外,您还可以使用range
函数像这样倒数
for index in range(len(list) - 1, -1, -1):
newlist.append(list[index])
您甚至不必自己增加 index
,for
循环会处理它。
正如@abarnert 所建议的,您实际上可以迭代列表并每次都在开头添加元素,就像这样
>>> def reverse(mylist):
... result = []
... for item in mylist:
... result.insert(0, item)
... return result
...
>>> reverse([1, 2, 3, 4, 5])
[5, 4, 3, 2, 1]
如果你想创建一个新的反向列表,你可能不必自己写一个函数,而是可以使用slicing notation来创建一个新的反向列表,像这样
>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]
但这不会改变原始对象。
>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]
>>> mylist
[1, 2, 3, 4, 5]
如果要改变原来的对象,只需将切片赋值回原来对象的切片,像这样
>>> mylist
[1, 2, 3, 4, 5]
>>> mylist[:] = mylist[::-1]
>>> mylist
[5, 4, 3, 2, 1]
注: reversed
actually returns a reverse iterator object, not a list. So, it doesn't build the entire list reversed. Instead it returns elements one by one when iterated with next
协议。
>>> reversed([1, 2, 3, 4, 5])
<list_reverseiterator object at 0x7fdc118ba978>
>>> for item in reversed([1, 2, 3, 4, 5]):
... print(item)
...
...
5
4
3
2
1
因此,您可能希望将其设为 generator function,像这样
>>> def reverse(mylist):
... for index in range(len(mylist) - 1, -1, -1):
... yield mylist[index]
...
...
>>> reverse([1, 2, 3, 4, 5])
<generator object reverse at 0x7fdc118f99d8>
所以 reverse
函数 returns 一个生成器对象。如果你想要一个列表,那么你可以用 list
函数创建一个,像这样
>>> list(reverse([1, 2, 3, 4, 5]))
[5, 4, 3, 2, 1]
如果你只是要一个一个地处理它,那么用一个 for
循环迭代它,就像这样
>>> for i in reverse([1, 2, 3, 4, 5]):
... print(i)
...
...
5
4
3
2
1
可能会检查一下:
def reverse(lst):
newList = []
countList = len(lst) - 1
for x in range(countList,-1,-1):
newList.append(lst[x])
return newList
def main():
lst = [9,8,7,6,5,4,2]
print(reverse(lst))
main()
要编写您尝试编写的函数,请参阅 。
但这不是 reverse
的工作方式,也不是它的作用。它不是创建新列表,而是就地修改现有列表。
如果您考虑一下,这很简单:只需遍历一半索引,对于每个索引 N,交换左起第 N 个和右起第 N 个。*
因此,坚持使用您现有的框架:
def reverse(lst):
index = 0
while index < len(lst)/2:
lst[index], lst[len(lst) - 1 - index] = lst[len(lst) - 1 - index], lst[index]
index = index + 1
附带说明一下,像这样使用 while
循环几乎总是一个坏主意。如果你想遍历一个数字范围,只需使用 for index in range(len(lst)):
。除了将三行代码减少为一行并使您所做的事情更加明显之外,它还删除了多个您可能会犯简单但调试起来很痛苦的错误的地方。
另外,请注意,在大多数情况下,在 Python 中,使用负数索引来表示 "from the right edge" 比自己计算更容易,而且它通常会删除一个可能的位置你很容易犯一个痛苦的错误。但在这种特殊情况下,它实际上可能不会更容易出错……
* 您必须确保考虑到边缘情况。对于奇数列表,您是否将中间元素与其自身交换并不重要,但只要确保您不会以错误的方式舍入并使一个元素走得太远或太短。这是学习如何编写好的单元测试的好机会……
我想分解 reverse() 函数并将其写成代码以供练习。我最终想出了如何去做(向后遍历原始列表并附加到新的 'reversed' 列表)但想知道为什么这不起作用。
def reverse(list):
newlist = []
index = 0
while index < len(list):
newlist[index] = list[(len(list)) - 1 - index]
index = index + 1
return newlist
list = [1, 2, 3, 4, 5]
print(reverse(list))
不能为长度为 0 的列表分配任意索引。这样做会引发 IndexError。由于您是按顺序分配元素,因此您可以只进行追加而不是对索引进行分配:
newlist.append(l[(len(l)) - 1 - index])
附加修改列表并自动增加其长度。
让您的原始代码工作的另一种方法是更改 newlist
的初始化,以便它有足够的长度来支持您的索引操作:
newlist = [None for _ in range(len(l))]
我还想指出,以内置类型和函数命名事物并不是一个好主意。这样做会影响内置函数的功能。
首先不要覆盖内置函数(list
在你的情况下)第二个 newlist
有一个 len
为 0 因此不能被索引访问。
def reverse(mylist):
newlist = [0] * len(mylist)
index = 0
while index < len(mylist):
newlist[index] = mylist[(len(mylist)) - 1 - index]
index = index + 1
return newlist
mylist = [1, 2, 3, 4, 5]
print(reverse(mylist))
您可以创建一个列表,其值与输入列表的长度相同,就像这样
newlist = [0] * len(mylist)
您需要使用 list.append
。 newlist[0]
是一个有效的操作,如果列表中至少有一个元素,但 newlist
在第一次迭代中是空的。此外,list
不是变量的好名称,因为有一个 python 内置容器同名:
def reverse(lst):
newlist = []
index = 0
while index < len(lst):
newlist.append(lst[(len(list)) - 1 - index])
index += 1
return newlist
list = [1, 2, 3, 4, 5]
print(reverse(list))
在 Python 中,如果索引不在 0 和列表长度 - 1 的范围内,则不能 access/update 列表的元素。
在您的例子中,您正试图分配给 0 处的元素,但列表为空。所以,它没有索引 0。这就是它失败并显示错误的原因,
IndexError: list assignment index out of range
相反,您可以使用 append
函数,像这样
newlist.append(list[(len(list)) - 1 - index])
除此之外,您还可以使用range
函数像这样倒数
for index in range(len(list) - 1, -1, -1):
newlist.append(list[index])
您甚至不必自己增加 index
,for
循环会处理它。
正如@abarnert 所建议的,您实际上可以迭代列表并每次都在开头添加元素,就像这样
>>> def reverse(mylist):
... result = []
... for item in mylist:
... result.insert(0, item)
... return result
...
>>> reverse([1, 2, 3, 4, 5])
[5, 4, 3, 2, 1]
如果你想创建一个新的反向列表,你可能不必自己写一个函数,而是可以使用slicing notation来创建一个新的反向列表,像这样
>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]
但这不会改变原始对象。
>>> mylist = [1, 2, 3, 4, 5]
>>> mylist[::-1]
[5, 4, 3, 2, 1]
>>> mylist
[1, 2, 3, 4, 5]
如果要改变原来的对象,只需将切片赋值回原来对象的切片,像这样
>>> mylist
[1, 2, 3, 4, 5]
>>> mylist[:] = mylist[::-1]
>>> mylist
[5, 4, 3, 2, 1]
注: reversed
actually returns a reverse iterator object, not a list. So, it doesn't build the entire list reversed. Instead it returns elements one by one when iterated with next
协议。
>>> reversed([1, 2, 3, 4, 5])
<list_reverseiterator object at 0x7fdc118ba978>
>>> for item in reversed([1, 2, 3, 4, 5]):
... print(item)
...
...
5
4
3
2
1
因此,您可能希望将其设为 generator function,像这样
>>> def reverse(mylist):
... for index in range(len(mylist) - 1, -1, -1):
... yield mylist[index]
...
...
>>> reverse([1, 2, 3, 4, 5])
<generator object reverse at 0x7fdc118f99d8>
所以 reverse
函数 returns 一个生成器对象。如果你想要一个列表,那么你可以用 list
函数创建一个,像这样
>>> list(reverse([1, 2, 3, 4, 5]))
[5, 4, 3, 2, 1]
如果你只是要一个一个地处理它,那么用一个 for
循环迭代它,就像这样
>>> for i in reverse([1, 2, 3, 4, 5]):
... print(i)
...
...
5
4
3
2
1
可能会检查一下:
def reverse(lst):
newList = []
countList = len(lst) - 1
for x in range(countList,-1,-1):
newList.append(lst[x])
return newList
def main():
lst = [9,8,7,6,5,4,2]
print(reverse(lst))
main()
要编写您尝试编写的函数,请参阅
但这不是 reverse
的工作方式,也不是它的作用。它不是创建新列表,而是就地修改现有列表。
如果您考虑一下,这很简单:只需遍历一半索引,对于每个索引 N,交换左起第 N 个和右起第 N 个。*
因此,坚持使用您现有的框架:
def reverse(lst):
index = 0
while index < len(lst)/2:
lst[index], lst[len(lst) - 1 - index] = lst[len(lst) - 1 - index], lst[index]
index = index + 1
附带说明一下,像这样使用 while
循环几乎总是一个坏主意。如果你想遍历一个数字范围,只需使用 for index in range(len(lst)):
。除了将三行代码减少为一行并使您所做的事情更加明显之外,它还删除了多个您可能会犯简单但调试起来很痛苦的错误的地方。
另外,请注意,在大多数情况下,在 Python 中,使用负数索引来表示 "from the right edge" 比自己计算更容易,而且它通常会删除一个可能的位置你很容易犯一个痛苦的错误。但在这种特殊情况下,它实际上可能不会更容易出错……
* 您必须确保考虑到边缘情况。对于奇数列表,您是否将中间元素与其自身交换并不重要,但只要确保您不会以错误的方式舍入并使一个元素走得太远或太短。这是学习如何编写好的单元测试的好机会……