轨道
/
Python
Python
/
练习
/
Chaitana 的巨型过山车
Chaitana 的巨型过山车

Chaitana 的巨型过山车

学习练习

简介

list是一种按_顺序_排列的可变元素集合。 像大多数集合一样(参见内置的tuple、dict和set),数组可以持有任意(或多种)数据类型的引用,包括其他数组。 数组可以通过切片语法整体或部分复制,也可以使用<list>.copy()来复制。 与任何序列一样,lists中的元素可以从左边按0-based index编号引用,也可以从右边按-1-based index编号引用。

数组既支持通用序列操作,也支持可变序列操作,例如min(<list>)/max(<list>)、<list>.index()、<list>.append()和<list>.reverse()。 可以使用for item in <list>结构遍历list中的元素。 当同时需要元素的下标和值时,可以使用for index, item in enumerate(<list>)。

Python 还提供了许多处理数组的实用数组方法。 下面会介绍其中一部分list methods。

注意,当你用list-method操作一个list时,你改变的是传入的那个数组对象。 如果你不想修改原来的list,至少需要通过切片或<list>.copy()对它做一个shallow copy。

添加元素

要把元素添加到已有数组的末尾,也就是“右侧”,可以使用<list>.append(<item>):

>>> numbers = [1, 2, 3]
>>> numbers.append(9)

>>> numbers
[1, 2, 3, 9]

与_追加_不同,<list>.insert()让你可以把元素添加到数组中的_指定下标_。 它接收 2 个形参:

  1. 你希望插入元素的<index>。
  2. 要插入的<item>。

注意:如果给定的index是 0,元素会被添加到list的开头(“左侧”)。 如果传入的index大于list上最后一个index,元素会被添加到最后一个位置,效果等同于使用<list>.append(<item>)。

>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)

>>> numbers
[-2, 1, 2, 3]

>>> numbers.insert(1, 0)

>>> numbers
[-2, 0, 1, 2, 3]

可以用<list>.extend(<item>)把一个已有的数组与另一个可迭代对象(例如set、tuple、str或list)中的元素合并起来。 这个可迭代对象会被_解包_,其中的元素会按顺序追加(在这种情况下使用<list>.append(<item>)会把整个可迭代对象作为单个元素添加进去。)。

>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]

>>> numbers.extend(other_numbers)

>>> numbers
[1, 2, 3, 5, 6, 7]

>>> numbers.extend([8, 9])

>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]

>>> numbers.append([8,9])

>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9, [8, 9]]

删除元素

要从数组中删除元素,使用<list>.remove(<item>),把要删除的元素作为实参传入。 如果要删除的元素不在list中,<list>.remove(<item>)会抛出ValueError。

>>> numbers = [1, 2, 3]
>>> numbers.remove(2)

>>> numbers
[1, 3]

# Trying to remove a value that is not in the list throws a ValueError
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list

另一种做法是使用<list>.pop(<index>)方法,它既能移除元素,也能把该元素return出来供使用。

<list>.pop(<index>)接受一个可选的形参:要移除并返回的元素的index。 如果没有指定(可选的)index实参,list的最后一个元素会被移除并返回。 如果指定的index大于最后一个元素的index,则会引发IndexError。

>>> numbers = [1, 2, 3]

>>> numbers.pop(0)
1

>>> numbers
[2, 3]

>>> numbers.pop()
3

>>> numbers
[2]

>>> numbers.pop(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: pop index out of range

可以用list.clear()移除list中的所有元素。它不接收任何形参。

>>> numbers = [1, 2, 3]
>>> numbers.clear()

>>> numbers
[]

反转与重排

<list>.reverse()方法会就地反转元素的顺序。

>>> numbers = [1, 2, 3]
>>> numbers.reverse()

>>> numbers
[3, 2, 1]

借助<list>.sort(),数组可以_就地重新排序。 默认的排序顺序是从左起的_升序。 Python 文档提供了更多排序技巧和方法。

Note

从 2002 年到 2022 年,Python 内部使用一种名为Timsort的算法来排列数组,但从Python 3.11起改用了Powersort。

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]

# The default sort order is *ascending*.
>>> names.sort()

>>> names
["Bruce", "Natasha", "Thor", "Tony"]

如果需要_降序_,就传入reverse=True实参:

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)

>>> names
["Tony", "Thor", "Natasha", "Bruce"]

如果不想修改原数组,可以使用内置的sorted(<iterable>)函数返回一个排好序的副本。

>>> names = ["Tony", "Natasha", "Thor", "Bruce"]

>>> sorted(names)
['Bruce', 'Natasha', 'Thor', 'Tony']

元素在数组中出现的次数

可以用list.count(<item>)计算某个元素在数组中出现的次数。 它把要统计的item作为实参,并返回该元素在list中出现的总次数。

>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]

>>> items.count(1)
3

查找元素的下标

<list>.index(<item>)会返回传入元素_第一次出现_的index编号。 如果没有出现,则会引发ValueError。 如果不需要元素的确切位置,用内置的in运算符检查数组是否包含某个给定的值会更高效。

下标从左边开始,以 0 为基准,所以“第一个”元素的位置是0。 下标也可以从右边开始,从-1起算。

>>> items = [7, 4, 1, 0, 2, 5]

>>> items.index(4)
1

>>> items.index(10)
ValueError: 10 is not in list

还可以提供start和end下标,把搜索范围缩小到list的某个特定区段:

>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]

>>> names.index("Tina")
0

>>> names.index("Tina", 2, 5)
3

说明

Chaitana 拥有一个非常受欢迎的主题公园。在风景优美的园区正中央,她只有一个游乐项目:世界最大的过山车(TM)。尽管只有这一个游乐设施,人们还是从世界各地赶来,排上几个小时的队,只为了能坐上 Chaitana 的超级过山车。

这个项目有两个队列,每个都用一个list来表示:

  1. 普通队列
  2. 快速队列(也叫 Fast-track),人们额外付费就能优先入场。

有人请你写一些代码,来更好地管理公园里的游客。你需要在游客(还有你的老板 Chaitana!)发飙之前,尽快把下面这些函数实现出来。请务必仔细阅读。有些任务要求你修改或更新已有的队列,有些则要求你复制一份。

1. 把我加进队列

定义add_me_to_the_queue()函数,它接受 4 个形参<express_queue>, <normal_queue>, <ticket_type>, <person_name>,返回相应的队列,其中已经加上了这个人的名字。

  1. <ticket_type>是一个int:1 表示 express_queue,0 表示 normal_queue。
  2. <person_name>是要加入相应队列的那个人的名字(类型为str)。
>>> add_me_to_the_queue(express_queue=["Tony", "Bruce"], normal_queue=["RobotGuy", "WW"], ticket_type=1, person_name="RichieRich")
...
["Tony", "Bruce", "RichieRich"]

>>> add_me_to_the_queue(express_queue=["Tony", "Bruce"], normal_queue=["RobotGuy", "WW"], ticket_type=0, person_name="HawkEye")
....
["RobotGuy", "WW", "HawkEye"]

2. 我的朋友们在哪儿?

有个人很晚才到公园,却想排到朋友们正等着的那个队列里。可是他不知道朋友们站在哪儿,而且手机也没信号,没法打电话问。

定义find_my_friend()函数,它接受 2 个形参queue和friend_name,返回这个名字在队列中的位置。

  1. <queue>是排队的人组成的list。
  2. <friend_name>是你要查找下标的那个朋友的名字(也就是他在队列中的位置)。

记住:下标从左边数从 0 开始,从右边数从 -1 开始。

>>> find_my_friend(queue=["Natasha", "Steve", "T'challa", "Wanda", "Rocket"], friend_name="Steve")
...
1

3. 我能加入他们吗?

既然已经找到了朋友们(在上面的任务 2 里),这位迟到的人就想插到朋友们排队的位置上。定义add_me_with_my_friends()函数,它接受 3 个形参queue、index和person_name。

  1. <queue>是排队的人组成的list。
  2. <index>是新成员要加入的位置。
  3. <person_name>是要加在下标位置上的那个人的名字。

返回更新后的队列,其中已经加上了这位迟到者的名字。

>>> add_me_with_my_friends(queue=["Natasha", "Steve", "T'challa", "Wanda", "Rocket"], index=1, person_name="Bucky")
...
["Natasha", "Bucky", "Steve", "T'challa", "Wanda", "Rocket"]

4. 队列里的讨厌鬼

你刚从队列那边听说,有个特别讨厌的人又推人、又大喊大叫,还在捣乱。你得把这个坏家伙赶出去,谁让他行为这么差!

定义remove_the_mean_person()函数,它接受 2 个形参queue和person_name。

  1. <queue>是排队的人组成的list。
  2. <person_name>是需要被赶出去的那个人的名字。

返回更新后的队列,其中已经去掉了这个讨厌鬼的名字。

>>> remove_the_mean_person(queue=["Natasha", "Steve", "Eltran", "Wanda", "Rocket"], person_name="Eltran")
...
["Natasha", "Steve", "Wanda", "Rocket"]

5. 同名的人

你可能没见过两个毫无血缘关系却长得一模一样的人,但你_肯定_见过毫无血缘关系、名字却完全相同的人(也就是同名的人)!今天到场的人里,这种人看起来还挺多。你想知道某个名字在队列里出现了多少次。

定义how_many_namefellows()函数,它接受 2 个形参queue和person_name。

  1. <queue>是排队的人组成的list。
  2. <person_name>是你认为可能在队列里出现不止一次的名字。

返回person_name出现的次数,类型为int。

>>> how_many_namefellows(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"], person_name="Natasha")
...
2

6. 移除最后一个人

可惜今天公园里人太多了,你需要把普通队列里的最后一个人移出去(你会给他一张代金券,让他改天再来走快速通道)。你得定义remove_the_last_person()函数,它接受 1 个形参queue,也就是排队的人组成的数组。

你应该更新这个list,同时也要return被移出去的那个人的名字,这样才能给他开一张代金券。

>>> remove_the_last_person(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"])
...
'Rocket'

7. 给队列排个序

出于管理上的需要,你需要把某个队列里的所有名字按字母顺序排好。

定义sorted_names()函数,它接受 1 个实参queue(排队的人组成的list),并返回这个list经过sorted排序后的副本。

>>> sorted_names(queue=["Natasha", "Steve", "Eltran", "Natasha", "Rocket"])
...
['Eltran', 'Natasha', 'Natasha', 'Rocket', 'Steve']
通过 GitHub 编辑 链接将在新窗口或新标签页中打开
Python Exercism

准备好开始 Chaitana 的巨型过山车 了吗?

注册 Exercism,借助 17 个概念146 个练习 和真人导师指导,学习并掌握 Python,全部免费。