Python-Core-50-Courses/第013课:列表和元组的应用.md

186 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## 第013课列表和元组的应用
列表和元组在编写应用程序时都非常有用,我们通过下面几个案例帮助大家熟悉列表和元组的使用方法。
### 经典的案例
#### 案例1成绩表和平均分统计。
> **说明**录入5个学生3门课程的考试成绩计算每个学生的平均分和每门课的平均分。
这个案例我们在之前说到过,而且提醒过大家在使用嵌套列表时应该避开的坑,下面我们给出完整的代码。
```Python
"""
录入5个学生3门课程的考试成绩
计算每个学生的平均分和每门课的平均分
Version: 0.1
Author: 骆昊
"""
names = ['关羽', '张飞', '赵云', '马超', '黄忠']
courses = ['语文', '数学', '英语']
# 用生成式创建嵌套的列表保存5个学生3门课程的成绩
scores = [[0] * len(courses) for _ in range(len(names))]
# 录入数据
for i, name in enumerate(names):
print(f'请输入{name}的成绩 ===>')
for j, course in enumerate(courses):
scores[i][j] = float(input(f'{course}: '))
print()
print('-' * 5, '学生平均成绩', '-' * 5)
# 计算每个人的平均成绩
for index, name in enumerate(names):
avg_score = sum(scores[index]) / len(courses)
print(f'{name}的平均成绩为: {avg_score:.1f}分')
print()
print('-' * 5, '课程平均成绩', '-' * 5)
# 计算每门课的平均成绩
for index, course in enumerate(courses):
# 用生成式从scores中取出指定的列创建新列表
curr_course_scores = [score[index] for score in scores]
avg_score = sum(curr_course_scores) / len(names)
print(f'{course}的平均成绩为:{avg_score:.1f}分')
```
上面对列表进行遍历的时候,使用了`enumerate`函数,这个函数非常有用。我们之前讲过循环遍历列表的两种方法,一种是通过索引循环遍历,一种是直接遍历列表元素。通过`enumerate`处理后的列表在循环遍历时会取到一个二元组,解包之后第一个值是索引,第二个值是元素,下面是一个简单的对比。
```Python
items = ['Python', 'Java', 'Go', 'Swift']
for index in range(len(items)):
print(f'{index}: {items[index]}')
for index, item in enumerate(items):
print(f'{index}: {item}')
```
#### 案例2设计一个函数返回指定日期是这一年的第几天。
> **说明**:这个案例源于著名的*The C Programming Language*上的例子。
```Python
"""
计算指定的年月日是这一年的第几天
Version: 0.1
Author: 骆昊
"""
def is_leap_year(year):
"""判断指定的年份是不是闰年平年返回False闰年返回True"""
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
def which_day(year, month, date):
"""计算传入的日期是这一年的第几天
:param year: 年
:param month: 月
:param date: 日
"""
# 用嵌套的列表保存平年和闰年每个月的天数
days_of_month = [
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
# 布尔值False和True可以转换成整数0和1因此
# 平年会选中嵌套列表中的第一个列表(2月是28天)
# 闰年会选中嵌套列表中的第二个列表(2月是29天)
days = days_of_month[is_leap_year(year)]
total = 0
for index in range(month - 1):
total += days[index]
return total + date
print(which_day(1980, 11, 28)) # 333
print(which_day(1981, 12, 31)) # 365
print(which_day(2018, 1, 1)) # 1
print(which_day(2016, 3, 1)) # 61
```
#### 案例3实现双色球随机选号。
> **说明**双色球属乐透型彩票范畴由中国福利彩票发行管理中心统一组织发行在全国范围内销售。红球号码范围为0133蓝球号码范围为0116。双色球每期从33个红球中开出6个号码从16个蓝球中开出1个号码作为中奖号码双色球玩法即是竞猜开奖号码的6个红球号码和1个蓝球号码。
这个题目的思路是用一个列表保存红色球的号码,然后通过`random`模块的`sample`函数实现无放回抽样这样就可以抽中6个不重复的红色球号码。红色球需要排序可以使用列表的`sort`方法,显示的时候一位数前面需要做补`0`的操作,可以用字符串格式化的方式来处理。
```Python
"""
双色球随机选号
Version: 0.1
Author: 骆昊
"""
from random import randint, sample
def display(balls):
"""输出列表中的双色球号码"""
for index, ball in enumerate(balls):
if index == len(balls) - 1:
print('|', end=' ')
print(f'{ball:0>2d}', end=' ')
print()
def random_select():
"""随机选择一组号码"""
# 用生成式生成1到33号的红色球
red_balls = [x for x in range(1, 34)]
# 通过无放回随机抽样的方式选中6个红色球
selected_balls = sample(red_balls, 6)
# 对红色球进行排序
selected_balls.sort()
# 用1到16的随机数表示选中的蓝色球并追加到列表中
selected_balls.append(randint(1, 16))
return selected_balls
n = int(input('机选几注: '))
for _ in range(n):
display(random_select())
```
> **提示**:彩票的本质是:**虚构一个不劳而获的事,去忽悠一群想不劳而获的人,最终养活一批真正不劳而获的人**。所以,**珍爱生命,远离各种形式的赌博**。
#### 案例4幸运的女人。
> **说明**有15个男人和15个女人乘船在海上遇险为了让一部分人活下来不得不将其中15个人扔到海里有个人想了个办法让大家围成一个圈由某个人开始从1报数报到9的人就扔到海里面他后面的人接着从1开始报数报到9的人继续扔到海里面直到将15个人扔到海里。最后15个女人都幸免于难15个男人都被扔到了海里。问这些人最开始是怎么站的哪些位置是男人哪些位置是女人。
上面这个问题其实就是著名的约瑟夫环问题。我们可以通过一个列表来保存这30个人是死是活的状态例如用布尔值`True`表示活着的人,用`False`表示被扔到海里的人。最开始的时候列表中的30个元素都是`True`,然后我们通过循环的方式去执行报数,找到要扔到海里的人并将对应的列表元素标记为`False`循环会执行到将列表中的15个元素标记为`False`,循环的过程中,列表的索引始终在`0`到`29`的范围,超过`29`就回到`0`,这样刚好可以形成一个闭环。
```Python
"""
幸运的女人(约瑟夫环问题)
Version: 0.1
Author: 骆昊
"""
persons = [True] * 30
# counter - 扔到海里的人数
# index - 访问列表的索引
# number - 报数的数字
counter, index, number = 0, 0, 0
while counter < 15:
if persons[index]:
number += 1
if number == 9:
persons[index] = False
counter += 1
number = 0
index += 1
index %= 30
for person in persons:
print('女' if person else '男', end='')
```
### 简单的总结
**列表和元组都很重要**,学会这两种数据类型,我们能做的事情又多了很多。
> **温馨提示**:学习中如果遇到困难,可以加**QQ交流群**询问。
>
> 付费群:**789050736**,群一直保留,供大家学习交流讨论问题。
>
> 免费群:**151669801**,仅供入门新手提问,定期清理群成员。