CSCI 1100 - 测试 2 概览与练习题

重要考试安排:

  • 第二次测试将于 2024 年 3 月 14 日 ( 星期四 ) 举行。
  • 大部分同学的考试时间为晚上 6:00 - 7:30。需要额外时间或安静环境的同学 ( 需提供相关证明 ) 将安排在单独的教室,并可能允许考试时间超过 7:30。
  • 考试教室分配将在考试前一天 ( 3 月 13 日,星期三 ) 晚上通过 Submitty 公布。
  • 考生必须:
    • 前往指定的考试教室
    • 携带身份证参加考试
    • 在正确的考区就座
    • 不得携带任何计算器、手机等电子设备,并摘下耳机、耳塞

违反以上任一规定可能导致考试成绩扣 20 分,违反所有规定最多可扣 80 分。

  • 在交卷前,考生不得离开考场 ( 即使是去洗手间 )。
  • 与第一次测试类似,本次考试允许携带一页小抄。

考试概览

考试范围

本次考试主要涵盖第 7-13 讲、实验 3-6 以及作业 2-5 的内容。元组 ( Tuple ) 和模块 ( Module ) 的相关知识点也在考试范围内,但不包括图像处理部分。

重点知识

  1. 列表 ( List ) 与元组:熟练掌握列表的各种操作 ( 如 append、insert、remove、连接、复制、切片等 ),理解元组、字符串与列表的区别。
  2. 控制结构:if 语句、while 与 for 循环、range、split、slice 的使用。
  3. 基本列表操作:比较两个列表中的元素、查找列表中特定元素、查找特定元素的索引 ( 最小值、最大值、满足特定条件的最后一个值 ),对列表中元素求和。
  4. 列表操作函数:编写函数判断列表是否包含特定类型的元素 ( 如负数、0、3 的倍数 ),并返回 True 或 False。
  5. 布尔值与比较:理解布尔值、比较运算以及布尔函数 and、or、not 的使用,能够对布尔表达式画出真值表。
  6. 文件操作:从文件中读取数据,以及其他文件操作。

列表的列表 ( 即二维列表 )

熟练使用列表的列表 ( 即二维列表 )。掌握使用嵌套循环输出二维列表,并练习检查给定元素在二维列表中的相邻元素。复习作业 5 的解题思路有助于巩固这部分内容。

其他知识点

虽然考试重点是上述内容,但也可能涉及之前实验、讲座和作业中的任何知识点。务必理解在函数中打印值、从函数返回值,以及同时打印和返回值之间的区别。

考试规则

考试过程中不得使用任何计算器、教科书、课堂笔记、智能手表或电子设备。但可以自行准备一张 A4 大小的双面小抄 ( 也可以小组合作准备 )。考试时每位考生必须持有自己的小抄,并在考试结束时与试卷一同上交。

样题与答案

本文提供了大量样题 ( 数量多于考试题 )。除了涉及 Python 输出的题目需要自行测试外,大部分题目的答案都将发布在 Submitty 的课程资源版块。需要编写 Python 代码的题目,代码长度不会超过 10-15 行,有的甚至更短。考试题目将与这些练习题以及作业、实验和课堂练习密切相关。

备考建议

  1. 与第一次测试相比,本次考试对语法的要求没那么严格,但也不能完全忽视。

  2. 学会阅读和跟踪代码,培养调试能力和代码理解能力。

  3. 练习将问题分解成小的、可管理的步骤。如果被一个大问题难住了,试着将其拆分成几个小问题,逐个解决。

  4. 在考试时,先浏览整张试卷,从最简单的题目开始做起,这样可以在开始时增强信心,并避免在难题上花太多时间。

  5. 仔细阅读每个题目,确保理解题目的要求。如有需要,可以在试卷上做标记或写下注释。

  6. 在考试过程中,如果遇到不会做的题目,先跳过,等其他题目完成后再回来思考。

  7. 在考试结束前,务必检查答题是否完整,确保没有遗漏任何题目或子问题。

  8. 管理好考试时间,避免在个别题目上花费过多时间。

  9. 保持冷静和自信的心态,相信自己的能力,发挥出最佳水平。

以上是对 CSCI 1100 第二次测试的全面概览,以及一些备考建议。希望大家能够合理安排时间,认真备考,在考试中取得优异的成绩。如果在复习过程中遇到任何问题,欢迎随时与老师或助教沟通。祝大家考试顺利!

练习题

比较日期

编写一个名为 compare_date 的 Python 函数,它接受两个列表作为参数,每个列表包含两个整数。每个列表按顺序包含一个月份和一个年份。如果第一个日期早于第二个日期,函数应返回 -1;如果两个日期相同,则返回 0;如果第一个日期晚于第二个日期,则返回 1。你的代码应该能处理月份和年份的任何合法输入。下面是一些示例调用和预期输出:

1
2
3
4
5
6
>>> compare_date( [10,1995], [8,1995] )
1
>>> compare_date( [5,2010], [5,2010] )
0
>>> compare_date( [10,1993], [8,1998] )
-1
此问题的答案

下面是一个 Python 函数,它将两个日期作为月份和年份的列表进行比较,并根据它们的顺序返回 -1、0 或 1:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def compare_date(date1, date2):
    month1, year1 = date1
    month2, year2 = date2
    
    if year1 < year2:
        return -1
    elif year1 > year2:
        return 1
    else:
        if month1 < month2:
            return -1
        elif month1 > month2:
            return 1
        else:
            return 0

解释:

  1. 函数 compare_date 接受两个参数 date1date2,它们是包含每个日期的月份和年份的列表。

  2. 我们将每个日期列表中的月份和年份解包到单独的变量中:month1year1month2year2

  3. 我们首先比较年份:

    • 如果 year1 小于 year2,我们返回 -1,因为第一个日期较早。
    • 如果 year1 大于 year2,我们返回 1,因为第一个日期较晚。
    • 如果 year1 等于 year2,我们继续比较月份。
  4. 如果年份相同,我们比较月份:

    • 如果 month1 小于 month2,我们返回 -1,因为第一个日期较早。
    • 如果 month1 大于 month2,我们返回 1,因为第一个日期较晚。
    • 如果 month1 等于 month2,我们返回 0,因为两个日期相同。

该函数可以正确处理月份和年份的任何合法输入。它首先比较年份,如果年份相同,再比较月份以确定日期的顺序。

你可以使用提供的示例调用来测试该函数:

1
2
3
print(compare_date([10, 1995], [8, 1995]))  # 输出:1
print(compare_date([5, 2010], [5, 2010]))   # 输出:0
print(compare_date([10, 1993], [8, 1998]))  # 输出:-1

该函数将为每个示例调用返回预期的输出。

找出最大的两个值

假设 v 是一个包含数字的列表。编写 Python 代码来查找并打印 v 中最大的两个值。如果列表只包含一个数字,则只打印该数字。如果列表为空,则不打印任何内容。例如,如果我们赋值

1
v = [ 7, 3, 1, 5, 10, 6 ]

那么你的代码的输出应该类似于

1
7 10

如果我们给定

1
v = [ 7 ]

那么你的代码的输出应该是

1
7
此问题的答案

下面是用于查找并打印列表 v 中最大两个值的 Python 代码:

1
2
3
4
5
6
7
if len(v) >= 2:
    highest = max(v)
    v.remove(highest)
    second_highest = max(v)
    print(second_highest, highest)
elif len(v) == 1:
    print(v[0])

解释:

  1. 我们首先使用 len() 函数检查列表 v 的长度。

  2. 如果 v 的长度大于或等于 2,说明列表中至少有两个元素。在这种情况下:

    • 我们使用 max() 函数找到列表中的最大值,并将其存储在变量 highest 中。
    • 我们使用 remove() 方法从列表中删除最大值。这样做是为了找到第二大的值。
    • 我们再次使用 max() 在更新后的列表中找到第二大的值,并将其存储在变量 second_highest 中。
    • 最后,我们打印 second_highesthighest 值,用空格分隔。
  3. 如果 v 的长度等于 1,说明列表中只有一个元素。在这种情况下:

    • 我们只需打印列表中的唯一元素,使用 v[0] 访问它。
  4. 如果 v 的长度为 0(即列表为空),代码将不会执行任何条件,并且不会打印任何内容。

示例:

  1. 如果 v = [7, 3, 1, 5, 10, 6],输出将是:

    1
    
    7 10
  2. 如果 v = [7],输出将是:

    1
    
    7
  3. 如果 v = [](空列表),将不会生成任何输出。

这段代码可以有效地查找并打印列表中的最大两个值,处理只有一个元素的情况,并且在列表为空时不做任何操作。

高评分意大利餐厅

考虑 Yelp 数据的简化版本,其中只提供了餐厅名称、餐厅类型和评分。假设这些值已经被读入一个列表的列表,格式如下:

1
2
3
4
5
restaurants = [ 
    [ 'Acme', 'Italian', 2, 4, 3, 5],
    [ 'Flintstone', 'Steak', 5, 2, 4, 3, 3, 4],
    [ 'Bella Troy', 'Italian', 1, 4, 5] 
]

编写一段 Python 代码,打印 restaurants 列表中所有没有 1 分评价且至少有一个 5 分评价的意大利餐厅。在上面的例子中,Acme 会被打印出来,但 FlintstoneBella Troy 不会。因为 Flintstone 不是意大利餐厅,而 Bella Troy 有一个 1 分的评价。你的代码应该适用于 restaurants 列表的任何合法格式。

此问题的答案

下面是打印 restaurants 列表中所有没有 1 分评价且至少有一个 5 分评价的意大利餐厅的 Python 代码:

1
2
3
for restaurant in restaurants:
    if restaurant[1] == 'Italian' and 1 not in restaurant[2:] and 5 in restaurant[2:]:
        print(restaurant[0])

解释:

  1. 我们使用 for 循环遍历 restaurants 列表中的每个餐厅。每个餐厅都表示为一个子列表。

  2. 在循环内部,我们使用 if 语句检查三个条件:

    • restaurant[1] == 'Italian':检查当前餐厅是否是意大利餐厅。
    • 1 not in restaurant[2:]:检查当前餐厅的评分中是否不存在 1 分。我们使用切片 restaurant[2:] 只考虑评分部分。
    • 5 in restaurant[2:]:检查当前餐厅的评分中是否存在 5 分。同样使用切片只考虑评分部分。
  3. 如果一个餐厅满足所有三个条件,说明它是一家没有 1 分评价且至少有一个 5 分评价的意大利餐厅。这时我们打印出该餐厅的名称,即子列表的第一个元素 restaurant[0]

  4. 循环继续处理 restaurants 列表中的下一个餐厅,直到检查完所有餐厅。

使用提供的示例 restaurants 列表:

1
2
3
4
5
restaurants = [
    ['Acme', 'Italian', 2, 4, 3, 5],
    ['Flintstone', 'Steak', 5, 2, 4, 3, 3, 4],
    ['Bella Troy', 'Italian', 1, 4, 5]
]

代码的输出将是:

1
Acme

只有 ‘Acme’ 被打印出来,因为它是唯一一家没有 1 分评价且至少有一个 5 分评价的意大利餐厅。‘Flintstone’ 不是意大利餐厅,‘Bella Troy’ 有一个 1 分评价,所以它们都不满足条件。

这段代码适用于任何符合指定格式的 restaurants 列表。

高平均评分餐厅

继续使用 Yelp 数据,假设你有以下代码

1
2
3
4
in_file = open('yelp.txt')
for line in in_file:
    p_line = parse_line(line)
    print(p_line)

并且 parse_line 函数会返回一个如下所示的列表

1
["Meka's Lounge", 42.74, -73.69, "Bars", [5, 2, 4, 4, 3, 4, 5], 3.857 ]

其中列表的最后一个元素是平均评分。修改上面的 for 循环,创建一个名为 high 的列表,存储所有平均评分至少为 4.0 的餐厅名称。你不需要打印 high 列表。

此问题的答案

要创建一个名为 high 的列表,存储所有平均评分至少为 4.0 的餐厅名称,你可以按如下方式修改 for 循环:

1
2
3
4
5
6
in_file = open('yelp.txt')
high = []
for line in in_file:
    p_line = parse_line(line)
    if p_line[-1] >= 4.0:
        high.append(p_line[0])

解释:

  1. for 循环之前,我们初始化一个名为 high 的空列表,用于存储高平均评分的餐厅名称。

  2. for 循环内部,我们使用 parse_line 函数解析文件的每一行,该函数返回一个包含餐厅信息的列表 p_line

  3. 我们使用条件 if p_line[-1] >= 4.0 检查 p_line 的最后一个元素(即平均评分)是否大于等于 4.0。

  4. 如果条件为真,说明该餐厅的平均评分至少为 4.0。这时我们使用 high.append(p_line[0]) 将餐厅的名称(即 p_line 的第一个元素)添加到 high 列表中。

  5. 循环继续处理文件中的下一行,直到处理完所有行。

循环结束后,high 列表将包含所有平均评分至少为 4.0 的餐厅名称。

例如,如果 yelp.txt 文件包含以下内容:

1
2
3
Meka's Lounge,42.74,-73.69,Bars,[5,2,4,4,3,4,5],3.857
Joe's Diner,40.71,-74.01,American,[4,3,5,4,4,5],4.167
Sushi Spot,37.78,-122.41,Japanese,[4,4,5,3,4,4,5],4.143

运行修改后的代码,high 列表将包含:

1
['Joe's Diner', 'Sushi Spot']

这些就是平均评分至少为 4.0 的餐厅名称。

根据要求,我们没有在代码中打印 high 列表。如果需要,该列表可用于后续操作。

国际象棋计分

在国际象棋游戏中,你通常可以通过加上你吃掉的棋子的分值来估计你的表现。棋子的分值如下:

1
2
3
4
5
P - (P)awn,兵,分值 = 1
B - (B)ishop,象,分值 = 3
K - (K)night,马,分值 = 3
R - (R)ook,车,分值 = 5
Q - (Q)ueen,后,分值 = 9

编写一个名为 chess_score 的 Python 函数,它接受一个字符串作为参数,返回字符串中棋子所代表的总分值。你可以假设字符串中只会出现 ‘P’、‘B’、‘K’、‘R’ 和 ‘Q’。不允许使用任何 if 语句和循环。例如,

1
print(chess_score('BQBP'))

应该输出 16,因为有 2 个象(每个 3 分)、1 个后(9 分)和 1 个兵(1 分)。

此问题的答案

下面是一个名为 chess_score 的 Python 函数,它计算由字符串表示的国际象棋棋子的总分值,不使用任何 if 语句或循环:

1
2
def chess_score(pieces):
    return pieces.count('P') + pieces.count('B') * 3 + pieces.count('K') * 3 + pieces.count('R') * 5 + pieces.count('Q') * 9

解释:

  1. 函数 chess_score 接受一个字符串 pieces 作为参数,表示吃掉的国际象棋棋子。

  2. 为了计算总分,我们使用字符串的 count() 方法来统计每种棋子出现的次数,并将其乘以对应的分值:

    • pieces.count('P'):计算字符串中兵(‘P’)的数量,并将其乘以 1(兵的分值)。
    • pieces.count('B') * 3:计算字符串中象(‘B’)的数量,并将其乘以 3(象的分值)。
    • pieces.count('K') * 3:计算字符串中马(‘K’)的数量,并将其乘以 3(马的分值)。
    • pieces.count('R') * 5:计算字符串中车(‘R’)的数量,并将其乘以 5(车的分值)。
    • pieces.count('Q') * 9:计算字符串中后(‘Q’)的数量,并将其乘以 9(后的分值)。
  3. 函数返回所有计算结果的总和,即吃掉棋子的总分值。

使用示例:

1
print(chess_score('BQBP'))

输出:

1
16

解释:

  • 字符串 ‘BQBP’ 包含 2 个象(‘B’)、1 个后(‘Q’)和 1 个兵(‘P’)。
  • 总分计算如下:
    • 2 个象 * 每个 3 分 = 6 分
    • 1 个后 * 9 分 = 9 分
    • 1 个兵 * 1 分 = 1 分
  • 总分为 6 + 9 + 1 = 16。

这个函数根据输入字符串表示的吃掉棋子计算国际象棋总分,不使用任何 if 语句或循环。它利用 count() 方法统计每种棋子的数量,并将它们乘以各自的分值,最后求和得到总分。

从文件中求整数之和

给你一个文件,每行输入包含三个以逗号分隔的整数。编写一个 Python 程序,分别对所有第一个、第二个和第三个整数求和,并将结果和全部输出在一行上,用逗号分隔。举个简单的例子,如果输入是

1
2
3
4
2, 5,7
3, 6, 10
1, 2, -3
2, 4, 1

那么输出应该是

1
8, 17, 15
此问题的答案

这是一个 Python 程序,它从文件中读取整数,根据它们的位置对它们求和,并输出结果和:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 打开文件进行读取
with open('input.txt', 'r') as file:
    # 初始化变量以存储和
    sum1 = 0
    sum2 = 0
    sum3 = 0
    
    # 从文件中读取每一行
    for line in file:
        # 将行拆分为单独的整数
        integers = line.strip().split(',')
        
        # 将整数转换为 int 并将它们添加到各自的和中
        sum1 += int(integers[0])
        sum2 += int(integers[1])
        sum3 += int(integers[2])
    
    # 打印结果和,用逗号分隔
    print(f"{sum1}, {sum2}, {sum3}")

解释:

  1. 我们首先使用 with 语句打开名为 ‘input.txt’ 的文件进行读取。这确保在我们读取完文件后文件被正确关闭。

  2. 我们初始化三个变量 sum1sum2sum3,分别存储第一个、第二个和第三个整数的和。

  3. 我们使用 for 循环从文件中读取每一行。file 对象是可迭代的,所以我们可以直接迭代它的行。

  4. 对于每一行,我们使用 strip() 方法删除任何前导或尾随空格,然后使用 split(',') 方法根据逗号分隔符将行拆分为单独的整数。这给了我们一个表示整数的字符串列表。

  5. 我们使用 int() 函数将每个整数字符串转换为实际的整数,并根据其在行中的位置将其添加到各自的和变量(sum1sum2sum3)中。

  6. 处理完所有行后,我们将最终和存储在 sum1sum2sum3 中。

  7. 最后,我们使用 print() 函数输出结果和,用逗号分隔。我们使用 f-string 来格式化输出,其中 {sum1}{sum2}{sum3} 是实际和值的占位符。

确保将输入数据保存在与 Python 脚本相同目录下名为 ‘input.txt’ 的文件中。当你运行脚本时,它将从文件中读取整数,计算和,并输出结果和,用逗号分隔。

生成数字序列

编写一行 Python 代码来生成以下数字序列

(a) [100, 99, 98, . . . , 0]
(b) [55, 53, 51, . . . ,−1]
(c) [3, 5, 7, 9, . . . , 29]
(d) [−95,−90,−85, . . . , 85, 90]

现在使用循环来完成。对于循环,你可以假设列表将在最后存储在变量 L 中。

此问题的答案

生成数字序列的一行 Python 代码:

(a) list(range(100, -1, -1))
(b) list(range(55, -2, -2))
(c) list(range(3, 30, 2))
(d) list(range(-95, 91, 5))

使用循环生成数字序列:

(a)

1
2
3
L = []
for i in range(100, -1, -1):
    L.append(i)

(b)

1
2
3
L = []
for i in range(55, -2, -2):
    L.append(i)

(c)

1
2
3
L = []
for i in range(3, 30, 2):
    L.append(i)

(d)

1
2
3
L = []
for i in range(-95, 91, 5):
    L.append(i)

解释:

  1. 一行 Python 代码:

    • 我们使用 range() 函数生成所需的数字序列。
    • range() 函数接受三个参数:start、stop 和 step。
      • start:序列的起始数字(包括)。
      • stop:序列的结束数字(不包括)。
      • step:序列中每个数字之间的差。
    • 我们用 list() 函数包装 range() 函数,将 range 对象转换为列表。
  2. 使用循环:

    • 我们初始化一个空列表 L 来存储数字。
    • 我们使用 for 循环迭代所需的数字序列。
    • 在循环内部,我们使用 append() 方法将每个数字添加到列表 L 中。
    • 循环参数与 range() 函数参数相同:
      • start:序列的起始数字(包括)。
      • stop:序列的结束数字(不包括)。
      • step:序列中每个数字之间的差。

这两种方法生成相同的数字序列。单行代码更简洁,而循环方法在需要时提供更大的灵活性和可定制性。

求和直到遇到负数

编写一个 while 循环,将列表 v 中的所有数字相加,直到遇到负数或达到列表末尾。将总和存储在变量 result 中。你的代码应该适用于 v 的任何只包含数字的版本。例如,对于以下两个列表,循环结束后 result 的值都应该是 25:

1
2
v = [ 10, 12, 3, -5, 5, 6 ]
v = [ 0, 10, 3, 6, 5, 1 ]
这个问题的答案

以下是使用 while 循环将列表 v 中的所有数字相加,直到遇到负数或达到列表末尾的 Python 代码:

1
2
3
4
5
6
i = 0
result = 0

while i < len(v) and v[i] >= 0:
    result += v[i]
    i += 1

解释:

  1. 我们初始化两个变量:

    • i:它作为索引变量,用于跟踪列表 v 中的当前位置。它从 0 开始,表示列表的第一个元素。
    • result:它存储数字的总和。它被初始化为 0。
  2. 我们使用两个条件启动一个 while 循环:

    • i < len(v):此条件检查索引 i 是否在列表 v 的范围内。它确保我们不会超出列表的最后一个元素。
    • v[i] >= 0:此条件检查索引 i 处的当前元素是否为非负数。它确保当我们遇到负数时停止添加数字。
  3. 在循环内部:

    • 我们使用 += 运算符将索引 i 处的当前元素添加到 result 变量中。这会累积数字的总和。
    • 我们使用 i += 1 将索引 i 增加 1,以移动到列表中的下一个元素。
  4. 循环继续,直到其中一个条件变为 false:

    • 如果 i 等于或大于 len(v),则意味着我们已经到达列表的末尾,循环终止。
    • 如果索引 i 处的当前元素为负数(v[i] < 0),则循环终止。
  5. 循环结束后,result 变量将包含列表 v 中所有数字的总和,直到遇到负数或到达列表的末尾。

让我们用给定的例子来测试代码:

示例 1:

1
v = [10, 12, 3, -5, 5, 6]

循环结束后,result 将是 25,因为当循环到达负数 -5 时停止。

示例 2:

1
v = [0, 10, 3, 6, 5, 1]

循环结束后,result 也将是 25,因为循环会一直添加数字,直到到达列表的末尾。

该代码适用于任何只包含数字的列表 v,并且在遇到负数或到达列表末尾时停止添加数字。

按递增顺序输出正值

编写 Python 代码,接受一个数字列表 v,并按递增顺序输出 v 中的正值,每行一个值。如果没有正值,则输出应为字符串 ‘None’。你可以假设列表中至少有一个值。例如,

1
v = [ 17, -5, 15, -3, 12, -5, 0, 12, 22, -1 ]

那么你的代码的输出应该是

1
2
3
4
5
12
12
15
17
22

作为第二个示例,如果

1
v = [ -17, -5, -15, -3, -12, -5, 0, -12, -22, -1 ]

那么输出应该只是

1
None
这个问题的答案

以下是接受一个数字列表 v,并按递增顺序输出正值(每行一个值),或者如果没有正值则输出 ‘None’ 的 Python 代码:

1
2
3
4
5
6
7
positive_values = sorted(filter(lambda x: x > 0, v))

if positive_values:
    for value in positive_values:
        print(value)
else:
    print('None')

解释:

  1. 我们使用 filter() 函数创建一个迭代器,该迭代器仅包含列表 v 中的正值。lambda 函数 lambda x: x > 0 用作过滤条件,对于大于 0 的值(正值)返回 True

  2. 我们将 filter() 返回的迭代器传递给 sorted() 函数,该函数按升序对正值进行排序。结果存储在 positive_values 列表中。

  3. 我们使用 if-else 语句检查 positive_values 列表中是否有任何正值:

    • 如果 positive_values 不为空(评估为 True),则意味着列表中有正值。
      • 我们使用 for 循环遍历 positive_values 中的每个值。
      • 在循环内部,我们使用 print() 函数在单独的行上输出每个正值。
    • 如果 positive_values 为空(评估为 False),则意味着列表中没有正值。
      • 我们使用 print() 函数输出字符串 ‘None’。

让我们用给定的例子来测试代码:

示例 1:

1
v = [17, -5, 15, -3, 12, -5, 0, 12, 22, -1]

输出:

1
2
3
4
5
12
12
15
17
22

示例 2:

1
v = [-17, -5, -15, -3, -12, -5, 0, -12, -22, -1]

输出:

1
None

对于第一个示例,代码正确地按递增顺序输出正值,每个值占一行。对于第二个示例,没有正值,它输出 ‘None’。

注意:如问题陈述中所述,代码假设列表 v 中至少有一个值。

列表操作输出

以下操作的输出是什么:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
>>> mylist = [1,4,8,12,6]
>>> x = mylist.sort()
>>> print(x)

>>> mylist = [1,4,8,12,6]
>>> slice1 = mylist[2:4]
>>> slice1[0] = 20
>>> print(slice1)

>>> print(mylist)
这个问题的答案

给定操作的输出如下:

操作 1:

1
2
3
>>> mylist = [1,4,8,12,6]
>>> x = mylist.sort()
>>> print(x)

输出:

1
None

解释:

  • sort() 方法就地对列表 mylist 进行排序,修改原始列表。
  • sort() 方法返回 None,而不是排序后的列表。
  • 当你将 mylist.sort() 的结果赋值给 x 时,x 变为 None
  • 打印 x 输出 None

操作 2:

1
2
3
4
>>> mylist = [1,4,8,12,6]
>>> slice1 = mylist[2:4]
>>> slice1[0] = 20
>>> print(slice1)

输出:

1
[20, 12]

解释:

  • mylist[2:4] 创建一个新列表 slice1,其中包含 mylist 从索引 2 到 3(不包括)的元素。
  • slice1 是一个独立于 mylist 的列表,修改 slice1 不会影响 mylist
  • slice1[0] = 20 将值 20 赋给 slice1 的第一个元素。
  • 打印 slice1 输出 [20, 12]

操作 3:

1
>>> print(mylist)

输出:

1
[1, 4, 8, 12, 6]

解释:

  • mylist 保持其原始状态 [1, 4, 8, 12, 6] 不变。
  • 在操作 2 中对 slice1 所做的修改不会影响 mylist
  • 打印 mylist 输出 [1, 4, 8, 12, 6]

总结:

  • 操作 1 输出 None,因为 sort() 就地修改列表并返回 None
  • 操作 2 输出 [20, 12],因为 slice1 是一个独立的列表,修改它不会影响 mylist
  • 操作 3 输出 [1, 4, 8, 12, 6],因为 mylist 保持其原始状态不变。

函数输出

下面这个程序的输出是什么?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def spam(a1,b1,a2,b2):
    if (a1 == a2) and (b1 > b2):
        return 1
    else:
        return 0

def egg(a1,b1,a2,b2):
    if (a1 > a2) and (b1 == b2):
        return 0
    else:
        return 1

a1 = 3
b1 = 4
a2 = 6
b2 = 4

print(spam(a2, b2, a1, b1))

print(egg(a1, b1, a2, b2))

c = spam(a1, b2, a2, b1)

print(c)

c += egg(a1, b2, a2, b1)

print(c)
这个问题的答案

给定程序的输出将是:

1
2
3
4
0
1
0
1

解释:

  1. 程序定义了两个函数:spam()egg()

  2. spam() 函数接受四个参数 (a1, b1, a2, b2),如果 a1 等于 a2 且 b1 大于 b2,则返回 1。否则,返回 0。

  3. egg() 函数接受四个参数 (a1, b1, a2, b2),如果 a1 大于 a2 且 b1 等于 b2,则返回 0。否则,返回 1。

  4. 程序初始化了四个变量:a1 = 3,b1 = 4,a2 = 6 和 b2 = 4。

  5. 第一个 print() 语句调用 spam() 函数,参数为 (a2, b2, a1, b1),即 (6, 4, 3, 4)。由于 a2 (6) 不等于 a1 (3),函数返回 0。因此,第一个输出是 0。

  6. 第二个 print() 语句调用 egg() 函数,参数为 (a1, b1, a2, b2),即 (3, 4, 6, 4)。由于 a1 (3) 不大于 a2 (6),函数返回 1。因此,第二个输出是 1。

  7. 变量 c 被赋值为调用 spam() 函数的结果,参数为 (a1, b2, a2, b1),即 (3, 4, 6, 4)。由于 a1 (3) 不等于 a2 (6),函数返回 0。因此,c 被赋值为 0。

  8. 第三个 print() 语句输出 c 的值,即 0。

  9. 代码行 c += egg(a1, b2, a2, b1) 等价于 c = c + egg(a1, b2, a2, b1)。它调用 egg() 函数,参数为 (a1, b2, a2, b1),即 (3, 4, 6, 4)。由于 a1 (3) 不大于 a2 (6),函数返回 1。返回值被加到 c 的当前值 0 上。因此,c 变为 1。

  10. 第四个 print() 语句输出 c 的更新值,即 1。

总之,程序输出:

  • 0(spam(a2, b2, a1, b1) 的结果)
  • 1(egg(a1, b1, a2, b2) 的结果)
  • 0(调用 spam(a1, b2, a2, b1)c 的值)
  • 1(将 egg(a1, b2, a2, b1) 的结果加到 c 的前一个值后 c 的值)

复制奇数行

编写一个名为 copy_half 的函数,它接受两个文件名作为参数。该函数应将第一个文件中的第一行、第三行、第五行等 (即仅奇数行) 复制到第二个文件中。例如,如果文件名是 ‘in.txt’ 和 ‘out.txt’,并且 ‘in.txt’ 包含

1
2
3
4
5
starting line
  not this line
middle line is here
    skip this line too
     I like this line

那么在调用

1
copy_half( 'in.txt', 'out.txt' )

之后,文件 ‘out.txt’ 应该包含

1
2
3
starting line
middle line is here
    I like this line
这个问题的答案

以下是问题的解决方案:

1
2
3
4
5
def copy_half(file1, file2):
    with open(file1, 'r') as input_file, open(file2, 'w') as output_file:
        lines = input_file.readlines()
        for i in range(0, len(lines), 2):
            output_file.write(lines[i])

解释:

  1. 函数 copy_half 接受两个参数:file1(输入文件)和 file2(输出文件)。

  2. 我们使用 with 语句打开两个文件,以确保在完成后正确关闭文件。我们以读取模式 (‘r’) 打开 file1,以写入模式 (‘w’) 打开 file2

  3. 我们使用 readlines() 读取输入文件中的所有行,并将它们存储在 lines 列表中。

  4. 我们启动一个 for 循环,使用 range(0, len(lines), 2) 以步长为 2 遍历 lines 的索引。这确保我们只处理奇数索引的行(第 1 行、第 3 行、第 5 行等)。

  5. 在循环内部,我们使用 output_file.write(lines[i]) 将每个奇数索引的行写入输出文件。这将输入文件中的行复制到输出文件中。

  6. 循环继续,直到处理并写入所有奇数索引的行到输出文件。

  7. 循环结束后,with 语句自动关闭两个文件。

因此,当你调用函数 copy_half('in.txt', 'out.txt') 时,它将读取 ‘in.txt’ 的内容,复制奇数索引的行(第 1 行、第 3 行、第 5 行等),并将它们写入 ‘out.txt’。生成的 ‘out.txt’ 文件将只包含 ‘in.txt’ 中的奇数行。

分离正负值

编写一段代码,从名为 test2.txt 的文件中读取整数,将正值存储在一个列表中,将负值存储在第二个列表中,并跳过空行和零。每个列表中的值的顺序应与输入的顺序相匹配。每行输入将包含空格或空格和一个整数。例如,如果 test2.txt 包含

1
2
3
4
5
    11
-3

5
  0

那么在你的代码之后,列表 P 应该是 [ 11, 5 ],列表 N 应该是 [ -3 ]

这个问题的答案

以下是从文件 test2.txt 中读取整数,将正值存储在列表 P 中,将负值存储在列表 N 中,并跳过空行和零的代码段:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
P = []
N = []

with open('test2.txt', 'r') as file:
    for line in file:
        line = line.strip()
        if line:
            num = int(line)
            if num > 0:
                P.append(num)
            elif num < 0:
                N.append(num)

解释:

  1. 我们初始化两个空列表:P 用于存储正值,N 用于存储负值。

  2. 我们使用 with 语句以读取模式打开文件 test2.txt,以确保在完成后正确关闭文件。

  3. 我们启动一个 for 循环,使用 for line in file: 遍历文件中的每一行。

  4. 对于每一行,我们使用 line.strip() 删除任何前导或尾随的空白字符(包括换行符)。

  5. 我们使用 if line: 检查剥离后的行是否不为空。此条件跳过空行。

  6. 如果行不为空,我们使用 int(line) 将其转换为整数,并将其存储在变量 num 中。

  7. 然后我们检查 num 的值:

    • 如果 num 大于 0,我们使用 P.append(num) 将其附加到列表 P
    • 如果 num 小于 0,我们使用 N.append(num) 将其附加到列表 N
    • 如果 num 等于 0,我们跳过它并继续下一行。
  8. 循环继续,直到处理完文件中的所有行。

  9. 循环结束后,with 语句自动关闭文件。

因此,在运行此代码段后,列表 P 将按照出现的顺序包含文件 test2.txt 中的正值,列表 N 将按照出现的顺序包含负值。空行和零将被跳过。

对于给定的示例,如果 test2.txt 包含:

1
2
3
4
5
    11
-3

5
  0

那么生成的列表将是:

  • P = [11, 5]
  • N = [-3]

代码输出 1

给出以下每段代码的输出

(a)

1
2
3
4
5
6
7
8
i = 4
L = [ 0, 12, 3, 5, 2, -1 ]
while 0 <= i and i < len(L):
    if L[i] < 0:
        break
    else:
        i = L[i]
print(i, L[i])

(b)

1
2
3
4
5
6
7
8
9
tough = 2
for i in range(2):
    s = 1
    for j in range(i, tough):
        s += tough
    print(s)
    print(tough)
    tough = s
    print(tough)
此问题的答案

(a) 输出:

1
2 3

解释:

  1. 变量 i 初始化为 4。
  2. 列表 L 定义为 [0, 12, 3, 5, 2, -1]
  3. while 循环以条件 0 <= i and i < len(L) 开始,由于 i 是 4 且 L 的长度是 6,条件为真。
  4. 在循环内部,检查条件 L[i] < 0。由于 L[4] 是 2,不小于 0,执行 else 块。
  5. else 块中,i 被赋值为 L[i],即 L[4] = 2。所以,i 变为 2。
  6. 循环继续更新后的 i 值,条件 0 <= i and i < len(L) 仍然为真。
  7. 再次检查条件 L[i] < 0。由于 L[2] 是 3,不小于 0,执行 else 块。
  8. else 块中,i 被赋值为 L[i],即 L[2] = 3。所以,i 变为 3。
  9. 循环继续更新后的 i 值,条件 0 <= i and i < len(L) 仍然为真。
  10. 再次检查条件 L[i] < 0。由于 L[3] 是 5,不小于 0,执行 else 块。
  11. else 块中,i 被赋值为 L[i],即 L[3] = 5。所以,i 变为 5。
  12. 循环继续更新后的 i 值,但条件 0 <= i and i < len(L) 现在为假,因为 i 是 5,不小于 L 的长度。
  13. 循环终止,打印 iL[i] 的值。此时,i 是 5,L[5] 是 -1。
  14. 因此,输出是 2 3

(b) 输出:

1
2
3
4
5
6
3
2
3
7
3
7

解释:

  1. 变量 tough 初始化为 2。
  2. 外部 for 循环从 i 的范围 0 到 1 开始(两次迭代)。
  3. 在第一次迭代(i = 0)中:
    • s 初始化为 1。
    • 内部 for 循环从 j 的范围 0 到 1 开始(两次迭代)。
    • 在内部循环的每次迭代中,s 增加 tough,即 2。所以,s 变为 3。
    • 内部循环结束后,打印 s,即 3。
    • 打印 tough,即 2。
    • tough 更新为 s 的值,所以 tough 变为 3。
    • 打印更新后的 tough 值,即 3。
  4. 在第二次迭代(i = 1)中:
    • s 初始化为 1。
    • 内部 for 循环从 j 的范围 1 到 2 开始(两次迭代)。
    • 在内部循环的每次迭代中,s 增加 tough,现在是 3。所以,s 变为 7。
    • 内部循环结束后,打印 s,即 7。
    • 打印 tough,即 3。
    • tough 更新为 s 的值,所以 tough 变为 7。
    • 打印更新后的 tough 值,即 7。
  5. 外部循环终止,程序结束。
  6. 因此,输出是:
    1
    2
    3
    4
    5
    6
    
    3
    2
    3
    7
    3
    7

代码输出 2

请显示以下代码的输出?

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def get_min(v):
    v.sort()
    return v[0]

def get_max(v):
    x = max(v)
    return x

v = [ 14, 19, 4, 5, 12, 8 ]
if len(v) > 10 and get_min(v) > 6:
    print("Hello")
    print(v[0])
    print(v[4])
else:
    print("So long")
    print(v[0])
    print(v[-1])
    
    if len(v) < 10 or get_max(v):
        print(get_max(v))
        print(v[0])
        print(get_min(v))
        print(v[0])
此问题的答案

给定代码的输出将是:

1
2
3
4
5
6
7
So long
4
19
19
4
4
4

解释:

  1. 列表 v 初始化为 [14, 19, 4, 5, 12, 8]
  2. 评估 if 条件 len(v) > 10 and get_min(v) > 6
    • len(v) 是 6,不大于 10。
    • 调用函数 get_min(v),它按升序对列表 v 进行排序并返回第一个元素,即 4。但是,4 不大于 6。
    • 由于两个条件都不满足,执行 else 块。
  3. else 块内:
    • 打印字符串 “So long”。
    • 打印 v[0],即 4。
    • 打印 v[-1],即 19。
  4. 评估下一个 if 条件 len(v) < 10 or get_max(v)
    • len(v) 是 6,小于 10,所以条件为真。
    • 调用函数 get_max(v),它返回列表 v 中的最大值,即 19。由于 19 是一个真值,条件也为真。
    • 由于任一条件为真,执行 if 语句内的块。
  5. if 块内:
    • 打印 get_max(v),即 19。
    • 打印 v[0],即 4。
    • 打印 get_min(v),即 4(因为列表 v 已经从之前调用 get_min() 进行了排序)。
    • 再次打印 v[0],即 4。
  6. 程序结束。

因此,输出将是:

1
2
3
4
5
6
7
So long
4
19
19
4
4
4

大象步数

显示以下代码的输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def elephant(height):
    time_step = 1
    steps = 0
    while steps < height:
        steps += time_step
        steps -= time_step//3
        time_step += 1
    print("{}, {}".format(time_step, steps))

elephant(0)
elephant(5)
elephant(6)
此问题的答案

给定代码的输出将是:

1
2
3
1, 0
5, 5
5, 6

解释:

  1. 定义函数 elephant(height),它接受一个整数 height 作为输入。
  2. 在函数内部:
    • 变量 time_step 初始化为 1。
    • 变量 steps 初始化为 0。
    • 开始一个 while 循环,只要 steps 小于 height 就继续。
    • 在循环内:
      • steps 增加 time_step
      • steps 减去 time_step // 3(整数除法)。
      • time_step 增加 1。
    • 循环结束后,使用格式字符串 "{}, {}" 通过 print() 函数打印 time_stepsteps 的值。
  3. 使用不同的参数调用函数 elephant()
    • elephant(0)
      • 由于 steps(0)不小于 height(0),不执行循环。
      • 打印 time_step(1)和 steps(0)的值。
    • elephant(5)
      • 循环迭代直到 steps 大于或等于 height(5)。
      • 在每次迭代中:
        • steps 增加 time_step(1, 2, 3, 4)。
        • steps 减去 time_step // 3(0, 0, 1, 1)。
        • time_step 增加 1。
      • 循环结束后,打印 time_step(5)和 steps(5)的值。
    • elephant(6)
      • 循环迭代直到 steps 大于或等于 height(6)。
      • 循环的行为与前一种情况类似,但由于 height 是 6,当 steps 变为 6 时循环结束。
      • 循环结束后,打印 time_step(5)和 steps(6)的值。
  4. 程序结束。

因此,输出将是:

1
2
3
1, 0
5, 5
5, 6

代码输出 3

显示以下代码的输出。确保我们能分辨出哪些是输出,哪些是草稿。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def remove_something(z):
    z.remove( z[z[0]] )

v = [ 1, 8, [12, 8], 'hello', 'car' ]
x = 'salad'

if len(v[2]) >= 2:
    if x > v[3]:
        print( 'One')
        if v[0] == 1:
            print('Three')
        else:
            print('Two')
    elif len(v) == 5:
        print('Six')
    else:
        v.append('five')
        print('Ten')
        
remove_something(v)
print(v[1])
print(v[2])
v.append(x)
print(len(v))
此问题的答案

输出:

1
2
3
4
Six
[12, 8]
hello
5

解释:

  1. 定义函数 remove_something(z),它从列表 z 中移除索引为 z[0] 的元素。
  2. 列表 v 初始化为 [1, 8, [12, 8], 'hello', 'car']
  3. 变量 x 被赋值为字符串 'salad'
  4. 评估 if 条件 len(v[2]) >= 2
    • v[2][12, 8],它的长度是 2,所以条件为真。
  5. 评估 if 条件 x > v[3]
    • x'salad'v[3]'hello'。由于 'salad' 在字典序上大于 'hello',条件为假。
  6. 评估 elif 条件 len(v) == 5
    • len(v) 是 5,所以条件为真。
    • 打印字符串 'Six'
  7. 使用 v 作为参数调用函数 remove_something(v)
    • 在函数内部,z[0] 是 1,所以 z[z[0]]z[1],即 8。
    • 从列表 v 中移除元素 8。
  8. 打印 v[1],现在是 [12, 8](因为 8 从列表中移除了)。
  9. 打印 v[2],现在是 'hello'(因为索引为 1 的元素被移除了)。
  10. 将字符串 x'salad')追加到列表 v 中。
  11. 打印 len(v),现在是 5(因为一个元素被移除,一个元素被添加)。
  12. 程序结束。

因此,输出将是:

1
2
3
4
Six
[12, 8]
hello
5

打印网格

给你一个列表的列表,表示为一个 NxN 的网格,其中每个列表对应网格的一行。例如,一个 4x4 的网格由以下给出:

1
[[1,2,3,4],[4,3,2,1],[2,1,4,2],[2,1,4,5]]

编写一段代码,以下列格式打印网格,在正中间有一条垂直和水平线:

1
2
3
4
5
1 2 | 3 4
4 3 | 2 1
----|----
2 1 | 4 2
2 1 | 4 5
此问题的参考答案

这是用 Python 打印所需格式的网格的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def print_grid(grid):
    n = len(grid)
    mid = n // 2

    for i in range(n):
        row = grid[i]
        for j in range(n):
            if j == mid:
                print("|", end=" ")
            print(row[j], end=" ")
        print()
        if i == mid - 1:
            print("-" * (n * 2 + 1))

# 使用示例
grid = [[1,2,3,4],[4,3,2,1],[2,1,4,2],[2,1,4,5]]
print_grid(grid)

解释:

  1. 函数 print_grid 接受一个列表的列表 grid 作为输入,表示 NxN 网格。

  2. 我们计算网格的长度 n 和中间索引 mid,方法是用整数除法 (//) 将 n 除以 2。

  3. 我们开始一个循环,使用索引 i 遍历网格的每一行。

  4. 对于每一行,我们使用 grid[i] 从网格中检索当前行 row

  5. 我们开始另一个循环,使用索引 j 遍历当前行的每个元素。

  6. 在内部循环中,我们检查当前列索引 j 是否等于中间索引 mid。如果是,我们打印一个竖线 (|),后面跟一个空格。

  7. 我们打印当前元素 row[j],后面跟一个空格。

  8. 打印完当前行的所有元素后,我们使用 print() 移动到下一行。

  9. 打印每一行后,我们检查当前行索引 i 是否等于 mid - 1。如果是,我们打印一条长度为 n * 2 + 1 的水平线 (-) (每行元素的数量乘以 2 再加 1,用于垂直线)。

  10. 最后,我们通过创建一个 4x4 的网格并使用网格作为参数调用函数,提供了 print_grid 函数的使用示例。

输出将是:

1
2
3
4
5
1 2 | 3 4 
4 3 | 2 1 
----|----
2 1 | 4 2 
2 1 | 4 5 

此代码以所需的格式打印网格,每行中间有一个竖线 (|),网格中间有一条水平线 (-)。

求和并计数

编写一段代码,使用 input 重复询问用户输入数字,直到用户输入 ‘stop’。然后,程序报告用户输入的值的总和以及严格大于零的值的总数。你可以假设用户输入有效的数字,直到她输入 stop。

下面给出了这段代码的一个运行示例。

1
2
3
4
5
6
7
Enter a value ==> 1.2
Enter a value ==> 0
Enter a value ==> 2
Enter a value ==> -1
Enter a value ==> stop
Sum: 2.2
Values > 0: 2
此问题的参考答案

这是 Python 代码,重复询问用户输入数字,直到输入 ‘stop’,然后报告值的总和和严格大于零的值的数量:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def sum_and_count_numbers():
    total_sum = 0
    count_positive = 0

    while True:
        user_input = input("Enter a value ==> ")
        if user_input == 'stop':
            break

        try:
            number = float(user_input)
            total_sum += number
            if number > 0:
                count_positive += 1
        except ValueError:
            print("Invalid input. Please enter a valid number.")

    print("Sum:", total_sum)
    print("Values > 0:", count_positive)

# 使用示例 
sum_and_count_numbers()

解释:

  1. 定义函数 sum_and_count_numbers 来执行所需的任务。

  2. 我们初始化两个变量: total_sum 用于跟踪用户输入的所有数字的总和,count_positive 用于计算严格大于零的值的数量。

  3. 我们使用 while True 开始一个无限循环,重复询问用户输入。

  4. 在循环内部,我们使用 input() 提示用户输入一个值,并将其存储在 user_input 变量中。

  5. 我们检查 user_input 是否等于 ‘stop’。如果是,我们使用 break 语句跳出循环,表示用户想要停止输入值。

  6. 如果 user_input 不是 ‘stop’,我们尝试使用 float() 将其转换为浮点数,并将其存储在 number 变量中。我们使用 try-except 块来处理用户输入无效时可能发生的任何潜在的 ValueError

  7. 如果成功转换为浮点数,我们使用 += 运算符将 number 添加到 total_sum 中。

  8. 然后我们使用条件 number > 0 检查 number 是否严格大于零。如果是,我们将 count_positive 变量增加 1。

  9. 如果在转换为浮点数时发生 ValueError,我们捕获异常并打印一条错误消息,通知用户输入有效的数字。

  10. 循环结束后 (当用户输入 ‘stop’ 时),我们使用 print() 打印 total_sumcount_positive 的值。

  11. 最后,我们通过调用它来提供 sum_and_count_numbers 函数的使用示例。

该代码将重复提示用户输入值,直到输入 ‘stop’。它将计算所有输入值的总和,并计算严格大于零的值的数量。输出将类似于问题中提供的示例运行。

从列表中删除值

编写一个函数 remove_val(l,val),从列表 l 中删除所有 val 的副本。

假设给你一个包含数字的变量 x,如下所示:

1
x = [1, 4, 2, 1, 2, 4, 4, 2, 5, 5, 2]

然后,你的函数应该像这样工作:

1
2
3
>>> remove_val(x,4)
>>> x
[1, 2, 1, 2, 2, 5, 5, 2]

注意:如果你的函数返回一个新列表而不是按给定的方式修改它,你将失去分数。另外,要小心这一点。代码:

(a)

1
2
3
4
def remove_val(l,val):
    for item in l:
        if item == val:
            l.remove(val)

(b)

1
2
3
4
def remove_val(l,val):
    for index in range(len(l)):
        if l[index] == val:
            l.pop(index)

将不起作用。你能解释为什么吗?尝试使用 while 循环编写 (a),看看这是否能让它更清晰。对于 (b),尝试在调试器中运行它。

此问题的参考答案

这是 remove_val 函数的正确实现,它从列表 l 中删除 val 的所有出现:

1
2
3
def remove_val(l, val):
    while val in l:
        l.remove(val)

解释:

  • 函数 remove_val 接受两个参数: l (列表) 和 val (要删除的值)。
  • 我们使用 while 循环重复检查 val 是否存在于列表 l 中,使用 in 运算符。
  • 如果在列表中找到 val,我们使用 list.remove() 方法删除它。
  • 循环继续,直到从列表中删除 val 的所有出现。

现在,让我们讨论为什么给定的实现 (a) 和 (b) 不能正确工作:

(a) 使用 for 循环:

1
2
3
4
def remove_val(l, val):
    for item in l:
        if item == val:
            l.remove(val)

解释:

  • 这个实现的问题是,它在使用 for 循环迭代列表时修改列表。
  • 当从列表中删除一个元素时,后续元素的索引会发生变化,导致循环跳过一些元素。
  • 因此,并非所有出现的 val 都从列表中删除。

(b) 使用 range()pop():

1
2
3
4
def remove_val(l, val):
    for index in range(len(l)):
        if l[index] == val:
            l.pop(index)

解释:

  • 这个实现也遇到了与 (a) 相同的问题。
  • 当使用 pop() 删除一个元素时,后续元素的索引会发生变化。
  • 然而,循环继续到下一个索引,可能会跳过与 val 匹配的元素。
  • 因此,并非所有出现的 val 都从列表中删除。

为了更清楚地理解这个问题,你可以在调试器中运行代码并逐步执行,看看每次删除后索引是如何变化的。

正确的方法是使用 while 循环,如第一个实现所示。它重复检查列表中是否存在 val,并将其删除,直到消除所有出现。

使用示例:

1
2
3
x = [1, 4, 2, 1, 2, 4, 4, 2, 5, 5, 2]
remove_val(x, 4)
print(x)  # 输出: [1, 2, 1, 2, 2, 5, 5, 2]

该函数通过删除值 4 的所有出现来修改原始列表 x

比较运动员成绩

假设给你两个运动员在各种比赛中的成绩,以两个单独的列表提供。假设有未知数量的比赛,编号为1、2、3等,两个列表的长度相同。

1
2
a1 = [11,8,11,9]
a2 = [11,9,8,12]

例如,根据这个列表,两名运动员在第1场比赛中都获得了11分。打印出 a2 表现更好的所有比赛的索引。例如,对于上述列表,我们将打印:

1
a2 is better in 2 4

如果没有 a2 更好的值,那么你应该打印:

1
a2 is never better
此问题的参考答案

这是一个 Python 脚本,用于比较两名运动员在各种比赛中的成绩,并打印出 a2 表现更好的比赛的索引:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def compare_scores(a1, a2):
    better_indices = []
    for i in range(len(a1)):
        if a2[i] > a1[i]:
            better_indices.append(i + 1)

    if better_indices:
        print("a2 is better in", ' '.join(map(str, better_indices)))
    else:
        print("a2 is never better")

# 使用示例
a1 = [11, 8, 11, 9]
a2 = [11, 9, 8, 12]
compare_scores(a1, a2)

解释:

  1. 函数 compare_scores 接受两个列表 a1a2 作为参数,表示两名运动员在各种比赛中的成绩。

  2. 我们初始化一个名为 better_indices 的空列表,用于存储 a2 表现更好的比赛的索引。

  3. 我们使用 range(len(a1)) 开始一个循环,遍历成绩的索引。由于假设两个列表的长度相同,我们可以使用任一列表的长度。

  4. 在循环内部,我们使用条件 a2[i] > a1[i] 比较每个索引处 a2a1 的成绩。如果 a2 在当前索引处有更高的分数,我们将索引加1追加到 better_indices 列表中。我们将索引加1,因为比赛的编号从1开始。

  5. 循环结束后,我们使用 if 语句检查 better_indices 列表是否不为空。

  6. 如果 better_indices 不为空,则表示 a2 至少在一场比赛中表现更好。我们打印 “a2 is better in”,后面是 a2 表现更好的比赛的索引。我们使用 join() 方法将索引连接成一个字符串,用空格分隔。map(str, better_indices) 用于在连接之前将索引转换为字符串。

  7. 如果 better_indices 为空,则表示 a2 在任何比赛中都没有表现更好。在这种情况下,我们打印 “a2 is never better”。

  8. 最后,我们通过使用给定的列表 a1a2 调用 compare_scores 函数,提供了一个使用示例。

对于示例列表,输出将是:

1
a2 is better in 2 4

这表明 a2 在第2场和第4场比赛中表现更好。

如果 a2 在任何比赛中都没有表现更好,输出将是:

1
a2 is never better

这个脚本比较了两名运动员的成绩,并打印出 a2 表现更好的比赛的索引,或者如果 a2 在任何比赛中都没有表现更好,则打印 “a2 is never better”。

列表切片输出

以下代码的输出是什么:

1
2
3
4
5
6
7
8
9
>>> L1 = ['cat', 'dog', 'hawk', 'tiger', 'parrot']
>>> print(L1[1:-1])
>>> print(L1[1:-2])
>>> print(L1[1:-4])
>>> print(L1[1:0])
>>> print(L1[1:10])
>>> print(L1[::-1])
>>> print(L1[1:4:2])
>>> print(L1[::-2])
此问题的参考答案

给定代码的输出如下:

1
2
3
4
5
6
7
8
['dog', 'hawk', 'tiger']
['dog', 'hawk']
[]
[]
['dog', 'hawk', 'tiger', 'parrot']
['parrot', 'tiger', 'hawk', 'dog', 'cat']
['dog', 'tiger']
['parrot', 'hawk', 'cat']

解释:

  1. print(L1[1:-1]):

    • 这将列表 L1 从索引1 (包括) 切片到倒数第二个索引 (不包括)。
    • 输出为 ['dog', 'hawk', 'tiger']
  2. print(L1[1:-2]):

    • 这将列表 L1 从索引1 (包括) 切片到倒数第三个索引 (不包括)。
    • 输出为 ['dog', 'hawk']
  3. print(L1[1:-4]):

    • 这将列表 L1 从索引1 (包括) 切片到倒数第五个索引 (不包括)。
    • 由于列表只有5个元素,这将导致一个空切片。
    • 输出为 []
  4. print(L1[1:0]):

    • 这将列表 L1 从索引1 (包括) 切片到索引0 (不包括)。
    • 由于结束索引小于起始索引,这将导致一个空切片。
    • 输出为 []
  5. print(L1[1:10]):

    • 这将列表 L1 从索引1 (包括) 切片到索引10 (不包括)。
    • 由于列表只有5个元素,结束索引超出了列表的长度,但不会导致错误。它只是包括从索引1到列表末尾的所有元素。
    • 输出为 ['dog', 'hawk', 'tiger', 'parrot']
  6. print(L1[::-1]):

    • 这将列表 L1 以步长为-1切片,即反转列表。
    • 输出为 ['parrot', 'tiger', 'hawk', 'dog', 'cat']
  7. print(L1[1:4:2]):

    • 这将列表 L1 从索引1 (包括) 切片到索引4 (不包括),步长为2。
    • 它包括指定范围内的每隔一个元素。
    • 输出为 ['dog', 'tiger']
  8. print(L1[::-2]):

    • 这将列表 L1 以步长为-2切片,即反转列表并包括每隔一个元素。
    • 输出为 ['parrot', 'hawk', 'cat']

这些示例演示了在 Python 中使用起始索引、结束索引和步长切片列表的不同方式。

代码输出 4

以下程序的输出是什么:

Part a

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
a = 25
b = 11
while True:
    print(a, b)
    if a <= 0 or b <= 0:
        break
    if a > b:
        a = a - b
    else:
        b = b - a
    b -= 1
    a += 1

Part b

1
2
3
4
5
mylist = [10, -5, 4, 8, 1000, -1, -120, 18, 5.2]
for item in mylist:
    if item < 0:
        continue
    print(item)

Part c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
def spam(l,s):
    m = len(s)//2
    s1 = s[:m]
    s2 = s[m:]
    if l.count(s1) == 0:
        l.append(s1)
    if l.count(s2) == 0:
        l.append(s2)

l = ['ab','cd','de','fg']
s1 = 'abcde'
s2 = 'fghi'
spam(l,s1)
print(s1)
l = spam(l,s2)
print(s2)
print(l)
此问题的参考答案

以下是每个程序的输出:

Part a

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
25 11
15 10
6 9
6 8
7 7
1 6
8 5
4 4
1 3
5 2
4 1
4 0

解释:

  • 程序从 a = 25b = 11 开始。
  • 它进入一个无限循环,并在每次迭代中打印 ab 的值。
  • 在循环内部,它检查 ab 是否小于或等于 0。如果是,它就跳出循环。
  • 如果 a 大于 b,它就从 a 中减去 b。否则,它从 b 中减去 a
  • 减法之后,它将 b 减 1,将 a 加 1。
  • 循环继续,直到满足中断条件,程序终止。

Part b

1
2
3
4
5
6
10
4
8
1000
18
5.2

解释:

  • 程序遍历 mylist 中的元素。
  • 对于每个元素,它使用条件 if item < 0 检查元素是否小于 0。
  • 如果元素小于 0,它使用 continue 语句跳过该元素,并移动到下一次迭代。
  • 如果元素大于或等于 0,它就打印该元素。
  • 程序继续,直到处理完 mylist 中的所有元素。

Part c

1
2
3
abcde
fghi
['ab', 'cd', 'de', 'fg', 'ab', 'cd', 'fg', 'hi']

解释:

  • 程序定义了一个函数 spam,它接受一个列表 l 和一个字符串 s 作为参数。
  • 在函数内部,它使用整数除法计算字符串 s 的中间索引 m
  • 它将字符串 s 分成两半: s1 (从开始到中间索引)和 s2 (从中间索引到结束)。
  • 它使用 l.count(s1) == 0 检查 s1 是否不在列表 l 中。如果是,它将 s1 附加到列表 l
  • 同样,它使用 l.count(s2) == 0 检查 s2 是否不在列表 l 中。如果是,它将 s2 附加到列表 l
  • 程序用 ['ab', 'cd', 'de', 'fg'] 初始化一个列表 l,以及两个字符串 s1s2
  • 它用 ls1 作为参数调用 spam 函数。
  • 它打印 s1 的值,该值保持不变。
  • 它再次用 ls2 作为参数调用 spam 函数,但返回值没有赋给任何变量。
  • 它打印 s2 的值,该值保持不变。
  • 最后,它打印更新后的列表 l,其中包括原始元素和 s1s2 中尚未出现在列表中的分割半部分。

这些程序演示了 Python 中不同的概念,如循环、条件、列表操作和函数调用。

更多 “输出是什么?” 的问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
print(4**3)
print(2**2**3)
----------------
for i in range(2,10,2):
    print(i)
----------------
j=2
while(j<10):
    print(j)
    j=j+2
L=[1,2,3,(7,8,'truck')]
L.insert(-1,L.pop())
print(L)
----------------
pokeballs = ["net", "ultra", "dusk", "great", "great", "great"]
while(True and pokeballs.pop() == "great"):
    print(pokeballs)
    print(pokeballs[-1] == "great")
----------------
list1 = [6,8,10]
list2 = [[3,5,7], list1, list(list1)]
list1.append(list2[0].pop())
print(list2)
----------------
j=11
while(True):
    print('-',end='')
    i=0
    if i >= 5:
        break
    elif j <= 4:
        break
    j = j - 1
    if j%2 == 1:
        continue
    print('*',end='')
    i = i + 2
----------------
a = "and".join(list("1234"))
b = a.split('and')
c = b
b.append('5')
c.append('6')
print(a)
print(b)
print(c)
c = b[:]
b.append('7')
c.append('8')
print(b)
print(c)
----------------
lst = ['dog', 'cat', 'chat']
print('dog' in lst and 'hat' in lst[2])
----------------
print(not True or True and False == False)
----------------
symbols = ['5', 'p', 'P', '100', '!', 'pika', 'Pika', 'pIka', '44']
print(sorted(symbols))
print(symbols[::].sort())
print(symbols)
print(symbols.sort())
print(symbols)
print(symbols[::-1])
----------------
def someFunc(myList, myTuple):
    myTuple = (4,3,2,1)
    for pikachu in myList:
        myList[pikachu-1] = str(pikachu) + "pika"
    return True
aList = [1, 2, 3, 4]
aTuple = (1, 2, 3, 4)
if someFunc(aList, aTuple):
    print(aTuple)
    print(aList)
----------------
waterTypes = ["Oshawott", "Froakie", "Squirtle", "Kyogre"]
print(waterTypes[0:3:2])
print(waterTypes[1::2])
print(waterTypes[-1:0:-2])
print(waterTypes[-2::-2])
wT2 = waterTypes[0:4:1].append("Magikarp")
print(wT2)
wT2 = waterTypes[0:4:1]
print(wT2)
print(wT2[:1] + wT2[-3:3] + wT2[-2:-3] + wT2[3:] + ["Magikarp"])
此问题的参考答案

以下是每个代码片段的输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
64
256
----------------
2
4
6
8
----------------
2
4
6
8
[1, 2, 3, (7, 8, 'truck')]
----------------
['net', 'ultra', 'dusk', 'great', 'great']
False
['net', 'ultra', 'dusk', 'great']
False
['net', 'ultra', 'dusk']
False
----------------
[[3, 5], [6, 8, 10, 7], [6, 8, 10]]
----------------
-*-*-*-*-*-
----------------
1and2and3and4
['1', '2', '3', '4', '5', '6']
['1', '2', '3', '4', '5', '6']
['1', '2', '3', '4', '5', '6', '7']
['1', '2', '3', '4', '5', '6', '8']
----------------
True
----------------
True
----------------
['!', '100', '44', '5', 'P', 'Pika', 'p', 'pIka', 'pika']
None
['!', '100', '44', '5', 'P', 'Pika', 'p', 'pIka', 'pika']
None
['!', '100', '44', '5', 'P', 'Pika', 'p', 'pIka', 'pika']
['pika', 'pIka', 'p', 'Pika', 'P', '5', '44', '100', '!']
----------------
(1, 2, 3, 4)
['1pika', '2pika', '3pika', '4pika']
----------------
['Oshawott', 'Squirtle']
['Froakie', 'Kyogre']
['Kyogre', 'Squirtle']
['Squirtle', 'Oshawott']
None
['Oshawott', 'Froakie', 'Squirtle', 'Kyogre']
['Oshawott', 'Squirtle', 'Kyogre', 'Kyogre', 'Magikarp']

每个代码片段的解释:

  1. 4**3 的结果是 64,2**2**3 的结果是 256,因为幂运算符 (**) 具有从右到左的结合性。

  2. for 循环以步长为 2 打印从 2 到 8 (包括 8)的偶数。

  3. while 循环以步长为 2 打印从 2 到 8 (包括 8)的偶数。

  4. 使用 L.pop() 弹出列表 L 的最后一个元素,并使用 L.insert(-1, ...) 将其插入到倒数第二个位置。打印结果列表。

  5. while 循环迭代,直到 pokeballs 的最后一个元素不等于 “great”。在每次迭代中,它打印 pokeballs 的当前状态和比较结果 pokeballs[-1] == "great"

  6. list2[0] 的最后一个元素被弹出并追加到 list1 中。打印结果的 list2

  7. while 循环根据条件和迭代次数打印一个由破折号和星号组成的模式。

  8. 字符串 “1234” 被分割成一个列表,用 “and” 连接,再次分割,结果列表通过追加元素进行修改。在不同阶段打印变量 abc

  9. 表达式 'dog' in lst and 'hat' in lst[2] 的结果为 True,因为两个条件都为真。

  10. 表达式 not True or True and False == False 由于操作顺序和操作数的真实性,结果为 True

  11. 使用 sorted() 按升序对列表 symbols 进行排序,并打印结果。在 symbols 及其切片上调用 sort() 方法,修改原始列表。使用步长为 -1 的切片打印反转后的列表。

  12. 函数 someFunc 通过在每个元素后面附加 “pika” 来修改 aList 的元素。元组 aTuple 保持不变。打印修改后的 aList 和原始的 aTuple

  13. waterTypes 列表上执行各种切片操作,并打印结果。在 waterTypes 的切片上调用 append() 方法,但返回值为 None。最后一行连接 wT2 的切片和一个新元素 “Magikarp” 以创建一个新列表。

从列表中删除元素 1

最后一个非常难的问题…问一下,我们可以在复习时讨论原因。

1
2
3
4
5
6
7
8
r = 10*[1]
for i in range(len(r)):
    r.remove(1)
print(r)
L = 10*[1]
for l in L:
    L.remove(l)
print(L)
此问题的参考答案

你提供的代码片段演示了两种尝试从列表中删除元素的不同方式,但两种方法都有问题。让我们分析每种情况:

情况 1:

1
2
3
4
r = 10*[1]
for i in range(len(r)):
    r.remove(1)
print(r)

解释:

  • 列表 r 初始化为包含 10 个值为 1 的元素。
  • for 循环使用 range(len(r)) 遍历 r 的索引。
  • 在每次迭代中,使用 r.remove(1)r 中删除第一次出现的 1
  • 然而,随着元素从列表中删除,剩余元素的索引会发生变化。
  • 循环继续到下一个索引,可能会跳过元素。
  • 因此,只有前 5 次出现的 1 被删除,最终的列表 r 包含 [1, 1, 1, 1, 1]

情况 2:

1
2
3
4
L = 10*[1]
for l in L:
    L.remove(l)
print(L)

解释:

  • 列表 L 初始化为包含 10 个值为 1 的元素。
  • for 循环直接遍历 L 的元素。
  • 在每次迭代中,使用 L.remove(l)L 中删除当前元素 l 的第一次出现。
  • 然而,在使用 for 循环遍历列表时修改列表会导致意外行为。
  • 随着元素被删除,后续元素的索引会发生变化,导致循环跳过一些元素。
  • 因此,只有交替出现的 1 被删除,导致最终的列表 L 包含 [1, 1, 1, 1, 1]

在这两种情况下,都没有达到删除列表中所有出现的 1 的预期结果。

要正确地从列表中删除元素的所有出现,你可以使用 while 循环,如前面的答案所示:

1
2
3
def remove_val(l, val):
    while val in l:
        l.remove(val)

这种方法重复检查 val 是否存在于列表 l 中,并删除它,直到所有出现都被消除。

使用示例:

1
2
3
4
5
6
7
r = 10*[1]
remove_val(r, 1)
print(r)  # 输出: []

L = 10*[1]
remove_val(L, 1)
print(L)  # 输出: []

在这两种情况下,所有出现的 1 都成功地从列表 rL 中删除,导致空列表。

在遍历列表时修改列表时要小心,因为它可能导致意外行为。使用 while 循环或创建一个包含所需元素的新列表是更安全的方法。

从列表中删除元素 2

好吧,这不是一个真正的 “输出是什么”,但类似。看看你能否解释这个:

1
2
3
4
r = 10*[1]
for i in range(len(r)):
    r.remove(r[i])
print(r)
此问题的参考答案

你提供的代码片段尝试使用 for 循环和 remove() 方法从列表 r 中删除元素,但它导致意外行为。让我们一步一步分析:

1
2
3
4
r = 10*[1]
for i in range(len(r)):
    r.remove(r[i])
print(r)

解释:

  1. 列表 r 初始化为包含 10 个值为 1 的元素。
  2. for 循环使用 range(len(r)) 遍历 r 的索引。
  3. 在每次迭代中,使用 r.remove(r[i])r 中删除索引 i 处的元素。
  4. 然而,随着元素从列表中删除,剩余元素的索引会发生变化。
  5. 循环继续到下一个索引,现在对应于一个与最初预期不同的元素。

让我们跟踪代码的执行:

  • 最初,r[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
  • 在第一次迭代 (i = 0) 中,r[0]1,所以 1r 中删除。删除后,r 变为 [1, 1, 1, 1, 1, 1, 1, 1, 1]
  • 在第二次迭代 (i = 1) 中,r[1] 现在是更新后列表中的第二个 1。它被删除,r 变为 [1, 1, 1, 1, 1, 1, 1, 1]
  • 在第三次迭代 (i = 2) 中,r[2] 现在是更新后列表中的第三个 1。它被删除,r 变为 [1, 1, 1, 1, 1, 1, 1]
  • 循环继续,从列表中删除每隔一个元素。

循环结束后,结果列表 r 将是 [1, 1, 1, 1, 1]

这段代码的问题在于,它在使用索引遍历列表时修改列表。随着元素被删除,后续元素的索引会发生变化,导致循环跳过一些元素,并导致意外行为。

要正确地从列表中删除元素的所有出现,你可以使用 while 循环,如前面的答案所示:

1
2
3
def remove_val(l, val):
    while val in l:
        l.remove(val)

这种方法重复检查 val 是否存在于列表 l 中,并删除它,直到所有出现都被消除。

使用示例:

1
2
3
r = 10*[1]
remove_val(r, 1)
print(r)  # 输出: []

在这种情况下,所有出现的 1 都成功地从列表 r 中删除,导致空列表。

在遍历列表时修改列表时要小心,因为它可能导致意外行为。使用 while 循环或创建一个包含所需元素的新列表是更安全的方法。

相关内容

0%