013:列表和元組的應用

有夢想的人不睡覺o0發表於2020-11-23

案例1:成績表和平均分統計

說明:錄入5個學生3門課程的考試成績,計算每個學生的平均分和每門課的平均分。

"""
錄入5個學生3門課程的考試成績
計算每個學生的平均分和每門課的平均分
"""
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處理後的列表在迴圈遍歷時會取到一個二元組,解包之後第一個值是索引,第二個值是元素,下面是一個簡單的對比。

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上的例子。

"""
計算指定的年月日是這一年的第幾天
"""
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:實現雙色球隨機選號

說明:雙色球屬樂透型彩票範疇,由中國福利彩票發行管理中心統一組織發行,在全國範圍內銷售。紅球號碼範圍為01~33,藍球號碼範圍為01~16。雙色球每期從33個紅球中開出6個號碼,從16個藍球中開出1個號碼作為中獎號碼,雙色球玩法即是競猜開獎號碼的6個紅球號碼和1個藍球號碼。

這個題目的思路是用一個列表儲存紅色球的號碼,然後通過random模組的sample函式實現無放回抽樣,這樣就可以抽中6個不重複的紅色球號碼。紅色球需要排序,可以使用列表的sort方法,顯示的時候一位數前面需要做補0的操作,可以用字串格式化的方式來處理。

"""
雙色球隨機選號
"""
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,迴圈的過程中,列表的索引始終在029的範圍,超過29就回到0,這樣剛好可以形成一個閉環。

"""
幸運的女人(約瑟夫環問題)
"""
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='')

 

相關文章