列表下标定位

题目考点

这道题主要考这几个知识点:

  1. 输入处理
  2. 字符串分割 split()
  3. 列表下标定位
  4. 循环累加
  5. 平均值计算
  6. 格式化输出,保留两位小数

这题表面上是在求平均分,真正的核心难点其实是:

列的顺序是不固定的,所以不能直接默认“第 2 列就是 MARKS”。

也就是说,这题真正考的是你能不能先从表头里找到 MARKS 在第几列,再去每一行里取对应位置的数据。


审题

输入是什么

输入一共分三部分:

第一行是一个整数 N,表示学生人数。

第二行是表头,也就是列名,包含这四个字段:

  • ID
  • MARKS
  • NAME
  • CLASS

但是这四列的顺序不固定。

接下来有 N 行,每一行都是一个学生的数据,顺序和表头对应。

输出是什么

输出所有学生 MARKS 的平均值,并且要保留两位小数。

这题要求我们真正做什么

这题不是简单地“读入每行然后取第二个数”。

而是要先解决两个问题:

  1. MARKS 这一列到底在第几列
  2. 每个学生这一行中,对应位置的分数是多少

找到之后,把所有分数加起来,再除以学生总人数 N

容易忽略的点

最容易错的地方就是这个:

列顺序不固定。

例如样例 1 里可能是:

ID MARKS NAME CLASS

但样例 2 里可能变成:

MARKS CLASS NAME ID

所以不能写死成:

marks = int(row[1])

因为 MARKS 不一定永远都在下标 1 的位置。


思路提示

先不要急着写代码,先把思路理顺。

你可以按下面 3 步想:

第一步:先读表头

表头这一行很关键,因为它告诉你每一列分别是什么。

比如:

MARKS CLASS NAME ID

这时候你应该先把它拆成一个列表:

['MARKS', 'CLASS', 'NAME', 'ID']

第二步:找到 MARKS 的位置

接着要想:

MARKS 在这个列表里的下标是多少?

比如上面这个例子里,MARKS 的下标就是 0

如果表头是:

ID MARKS NAME CLASS

MARKS 的下标就是 1

所以,我们其实是在“动态定位分数列”。

第三步:每读一行学生数据,就取这一列的值

比如某一行是:

92 2 Calum 1

如果我们已经知道 MARKS 的下标是 0,那这一行的分数就是:

row[0]

如果 MARKS 的下标是 1,那就取:

row[1]

最后把所有分数加起来,除以 N 就行。


完整设计思路

这道题可以拆成非常清楚的 4 步。

第 1 步:读取学生人数

先读取 N

n = int(input())

这个 n 后面有两个作用:

  1. 知道后面要读多少行学生数据
  2. 最后求平均分时用来做除数

第 2 步:读取表头并找到 MARKS 所在位置

读入表头:

columns = input().split()

例如输入:

MARKS CLASS NAME ID

就会变成:

['MARKS', 'CLASS', 'NAME', 'ID']

然后找到 MARKS 的下标:

marks_index = columns.index('MARKS')

这个 marks_index 就是后面取分数的关键。

第 3 步:循环读取每个学生的数据并累加分数

准备一个总分变量:

total = 0

然后循环 n 次,每次读一行:

row = input().split()

这一行也会变成一个列表。

因为我们已经知道了 MARKS 的位置,所以可以直接取:

row[marks_index]

再把它转成整数,加到总分里:

total += int(row[marks_index])

第 4 步:计算平均值并格式化输出

平均分就是:

average = total / n

题目要求保留两位小数,所以输出时要格式化:

print(f"{average:.2f}")

这里的 .2f 表示保留两位小数。


代码实现

下面给你一个适合初学者、很直白的写法。

if __name__ == '__main__':
    n = int(input())
    columns = input().split()

    marks_index = columns.index('MARKS')

    total = 0

    for _ in range(n):
        row = input().split()
        total += int(row[marks_index])

    average = total / n
    print(f"{average:.2f}")

运行演示

我们拿题目的第二组样例来手动走一遍。

输入是:

5
MARKS CLASS NAME ID
92 2 Calum 1
82 5 Scott 2
94 2 Jason 3
55 8 Glenn 4
82 2 Fergus 5

第一步:读取 n

n = 5

说明一共有 5 个学生。

第二步:读取表头

columns = ['MARKS', 'CLASS', 'NAME', 'ID']

找到 MARKS 的位置:

marks_index = 0

第三步:逐行累加

第一行:

row = ['92', '2', 'Calum', '1']

MARKS 在下标 0,所以分数是:

row[0] = '92'

转成整数后加入总分:

total = 92

第二行:

row = ['82', '5', 'Scott', '2']

分数是 82

total = 174

第三行:

row = ['94', '2', 'Jason', '3']

分数是 94

total = 268

第四行:

row = ['55', '8', 'Glenn', '4']

分数是 55

total = 323

第五行:

row = ['82', '2', 'Fergus', '5']

分数是 82

total = 405

第四步:求平均分

average = 405 / 5 = 81.0

格式化保留两位小数后输出:

81.00

方法总结

这道题很适合作为一种“表头定位题”的模板来记。

以后你看到这种题目时,如果题目说:

  • 列顺序可能变化
  • 字段名固定但位置不固定
  • 某一列要被提取出来计算

你就要立刻想到这个做法:

通用思路

先读表头
再找目标列名的位置
再按这个位置去每一行取值

可以把它记成一句话:

先找列,再取值。

这类题的固定模板

n = int(input())
columns = input().split()
target_index = columns.index('目标列名')

for _ in range(n):
    row = input().split()
    value = row[target_index]

这个模板以后会很常见,不只是 MARKS,也可能是 IDNAME,或者别的字段。


易错点提醒

1. 把 MARKS 的位置写死

错误思路:

total += int(row[1])

这是假设 MARKS 永远在第 2 列,但题目明确说了列顺序不固定。

2. 忘记把分数字符串转成整数

input().split() 拿到的内容默认都是字符串。

所以:

row[marks_index]

拿到的还是 '92',不是数字 92

必须写:

int(row[marks_index])

3. 平均值输出格式不对

题目要求保留两位小数,所以不能只写:

print(average)

更稳妥的写法是:

print(f"{average:.2f}")

本节小结

这题表面在求平均数,本质在考你能不能根据表头动态定位某一列。

真正的关键不是“怎么算平均分”,而是:

  1. 表头先拆成列表
  2. index() 找到 MARKS
  3. 每一行都按这个下标取分数
  4. 累加后求平均
  5. 用两位小数输出

这类题以后你一旦看到“列顺序不固定”,就要立刻想到 index()


练习

你可以先自己做这道同类型小练习:

已知输入格式如下:

第一行是整数 n
第二行是列名,包含 ID NAME CLASS AGE,顺序不固定。
接下来 n 行是每个学生的数据。
请输出所有学生 AGE 的平均值,保留两位小数。

提示

这道题和刚才几乎一模一样,只需要把:

'MARKS'

改成:

'AGE'

然后把每一行里对应位置的年龄取出来累加即可。

marks_index = columns.index(‘MARKS’)

先说结论:这句代码到底在干什么

marks_index = columns.index('MARKS')

这句话的作用可以直接翻译成一句大白话:

columns 这个列表里,去找 'MARKS' 这个元素出现的位置,然后把这个位置记录到 marks_index 里。

也就是说,它不是在找分数本身,而是在找:

“分数这一列在哪一列。”

这正是这道题最关键的一步。


先理解 columns 到底是什么

在这道题里,前面通常会有这样一句:

columns = input().split()

假设输入这一行是:

ID MARKS NAME CLASS

那么 split() 之后,columns 就会变成一个列表:

['ID', 'MARKS', 'NAME', 'CLASS']

所以这时候:

columns

不是一个字符串,而是一个列表

你可以把它理解成:

“表头这一行,被拆成了一个一个单词,按顺序装进列表里。”


再看 .index('MARKS') 是什么意思

index()列表的一个方法

它的作用是:

查找某个元素在列表中第一次出现的位置。

例如:

a = ['apple', 'banana', 'orange']
print(a.index('banana'))

输出就是:

1

因为 'banana' 在列表里的位置是下标 1。

所以:

columns.index('MARKS')

意思就是:

columns 这个列表中,找到 'MARKS' 的下标。


为什么返回的是 1,而不是 2

这是初学者非常容易混乱的地方。

Python 列表的下标是从 0 开始的,不是从 1 开始。

比如:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']

它们的位置实际上是:

元素下标
'ID'0
'MARKS'1
'NAME'2
'CLASS'3

所以:

columns.index('MARKS')

返回的是:

1

不是 2。

因为 Python 认为第一个位置是 0,第二个位置才是 1。


整句代码要拆成三部分看

第一部分:columns

这是一个列表,里面装着表头名称。

例如:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']

第二部分:.index('MARKS')

这是在列表中查找 'MARKS' 所在位置。

得到结果:

1

第三部分:marks_index = ...

这是把找到的位置保存到变量 marks_index 里。

于是最后:

marks_index = 1

为什么这里必须写 'MARKS',还要加引号

因为 'MARKS' 是一个字符串内容,表示我们要找的列名。

如果你写成:

columns.index(MARKS)

Python 会以为你在找一个叫 MARKS 的变量。

如果这个变量根本没有定义,就会报错:

NameError

所以这里必须写成字符串:

'MARKS'

意思是:

“我要找的是这个单词本身,不是某个变量。”


手动模拟一遍这句代码是怎么执行的

假设表头这一行输入的是:

MARKS CLASS NAME ID

执行:

columns = input().split()

之后,columns 变成:

['MARKS', 'CLASS', 'NAME', 'ID']

然后执行:

marks_index = columns.index('MARKS')

Python 会做这样的事情:

先看第 0 个元素是不是 'MARKS'

columns[0] == 'MARKS'

结果为真,所以立刻返回 0

于是:

marks_index = 0

再看另一种情况。

如果表头是:

ID NAME CLASS MARKS

那么:

columns = ['ID', 'NAME', 'CLASS', 'MARKS']

执行:

columns.index('MARKS')

Python 会这样找:

先检查 columns[0],也就是 'ID',不是
再检查 columns[1],也就是 'NAME',不是
再检查 columns[2],也就是 'CLASS',不是
再检查 columns[3],也就是 'MARKS',找到了

于是返回:

3

最后:

marks_index = 3

为什么这一步在这道题里这么关键

因为题目明确说了:

列的顺序可以变化。

这就意味着,MARKS 这一列有时候在第 2 列,有时候在第 1 列,有时候甚至在最后一列。

所以你不能写死:

row[1]

因为这相当于你假设:

“分数永远都在下标 1 的位置。”

但题目不保证这一点。

正确做法是先用:

marks_index = columns.index('MARKS')

找到分数列的真实位置。

然后再去每一行里写:

row[marks_index]

这才是“跟着表头走”的做法。


它和 row[marks_index] 是怎么配合起来工作的

这是最关键的一层理解。

假设:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']

那么:

marks_index = columns.index('MARKS')

得到:

marks_index = 1

接着某一行学生数据是:

row = ['1', '97', 'Raymond', '7']

因为 MARKS 在下标 1,所以:

row[1]

就是:

'97'

也就是说:

row[marks_index]

就等价于:

row[1]

于是你就能拿到这一行对应的分数。

所以这整套逻辑其实是:

先在表头里找到“分数列的位置”
再去每一行的同样位置拿“分数值”

你可以把它理解成:

表头负责定位,数据行负责取值。


为什么不能直接写 columns['MARKS']

因为列表和字典不一样。

columns 是一个列表,比如:

['ID', 'MARKS', 'NAME', 'CLASS']

列表取值只能用数字下标:

columns[0]
columns[1]

不能这样写:

columns['MARKS']

因为 'MARKS' 不是数字下标。

所以你必须先把 'MARKS' 变成数字位置,这正是 index() 在做的事。


如果找不到 'MARKS' 会怎么样

如果列表里根本没有 'MARKS',比如:

columns = ['ID', 'NAME', 'CLASS']

那么执行:

columns.index('MARKS')

会报错:

ValueError: 'MARKS' is not in list

意思是:

“我在这个列表里根本没找到 'MARKS'。”

不过这道题已经告诉你,列名一定是 ID、MARKS、CLASS、NAME 这几个,所以正常情况下不用担心这个问题。


你可以把这句代码翻译成中文模板

以后你看到这种代码,可以直接脑中翻译:

something_index = list_name.index('目标内容')

翻译成:

list_name 这个列表里,找到 '目标内容' 的位置,并把这个位置保存到 something_index 变量中。

比如:

name_index = columns.index('NAME')

意思就是:

在表头列表里,找到 NAME 这一列的位置。

又比如:

id_index = columns.index('ID')

意思就是:

找到 ID 这一列的位置。


用一个生活化比喻理解

你可以把 columns 想成教室里一排贴好的标签:

['ID', 'MARKS', 'NAME', 'CLASS']

现在老师说:“去找 MARKS 这个标签在第几个位置。”

你就从左往右看:

  • 第 0 个是 ID
  • 第 1 个是 MARKS

所以你记住:

marks_index = 1

接着每一行学生数据,就像一排具体的信息:

['1', '97', 'Raymond', '7']

你已经知道“分数在第 1 个位置”,那就去拿第 1 个位置的值,也就是 97


初学者最容易卡住的 3 个误区

误区 1:以为 index() 找到的是值本身

不是。

columns.index('MARKS')

找到的不是分数,不是 97,也不是平均分。

它找到的是:

MARKS 这个字段在表头中的位置。


误区 2:以为 index() 会返回第几个,从 1 开始算

不是。

Python 下标从 0 开始,所以返回的是 0、1、2、3 这种数字。


误区 3:以为这一句是在处理学生数据行

也不是。

这句代码处理的是表头,不是学生具体数据。

表头负责告诉你“哪一列是什么”,学生数据行负责告诉你“这一列的具体值是多少”。


最后把这句代码和整题主线重新连起来

这道题的主线是:

先读学生人数
再读表头
然后找到 MARKS 的位置
接着读每一行学生数据
每次取出那一列的分数
最后求平均值

所以这句代码:

marks_index = columns.index('MARKS')

它的本质作用就是:

把“列名”变成“下标”。

而只有完成这一步,你后面才能写:

total += int(row[marks_index])

如果没有这一步,你就不知道每行数据里应该取哪一个位置。


一句最关键的总结

请你把这句记成这样:

columns.index('MARKS') 不是在找分数,而是在找“分数这一列在哪儿”。


小练习

你先不要看答案,自己想一想下面这几个结果分别是什么。

已知:

columns = ['NAME', 'CLASS', 'ID', 'MARKS']

请判断:

  1. columns.index('NAME') 的结果是什么
  2. columns.index('ID') 的结果是什么
  3. columns.index('MARKS') 的结果是什么
  4. 如果某一行数据是 ['Tom', '5', '12', '88'],那么分数应该取 row[几]

提示

先找 MARKS 在表头里的位置,再去同样的位置拿分数。

为什么 row[marks_index] 这个写法,能刚好取到每一行对应的分数

这一点其实是整道题最核心的“对应关系”问题。

很多初学者前面能接受:

marks_index = columns.index('MARKS')

但是到了下一步:

row[marks_index]

就会开始疑惑:

为什么这个下标,放到每一行学生数据里,也还能继续用?而且还刚好取到分数?

答案就在一句话里:

因为每一行数据的列顺序,和表头 columns 的顺序是完全一致的。

也就是说,表头第几个位置表示什么,每一行数据的第几个位置就放的是什么。


先抓住这道题最根本的规则

题目说的是:

后面每一行数据,都是“在各自对应的列下面”。

这句话很重要。

意思就是,如果表头是:

ID MARKS NAME CLASS

那么下面每一行就一定是:

ID对应的数据 MARKS对应的数据 NAME对应的数据 CLASS对应的数据

比如:

1 97 Raymond 7

它不是随便排的,而是严格按表头来的:

表头位置表头内容这一行对应的数据
0ID1
1MARKS97
2NAMERaymond
3CLASS7

所以你一旦知道:

marks_index = 1

那你就知道:

每一行的下标 1 位置,一定就是分数。

于是:

row[marks_index]

实际上就是:

row[1]

也就是这一行的分数 97


先把 columnsrow 看成两行“对齐”的列表

这是最推荐你建立的脑中画面。

假设输入是:

ID MARKS NAME CLASS
1 97 Raymond 7

执行后:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']
row = ['1', '97', 'Raymond', '7']

你不要把它们看成两个毫不相关的列表。

你应该把它们看成上下对齐的两排:

下标0123
columnsIDMARKSNAMECLASS
row197Raymond7

这时候你就会很清楚地看到:

  • columns[0] 对应 row[0]
  • columns[1] 对应 row[1]
  • columns[2] 对应 row[2]
  • columns[3] 对应 row[3]

所以如果 MARKScolumns[1],那么分数就一定在 row[1]

这就是:

row[marks_index]

为什么能取到对应分数的根本原因。


本质上,这是“同列同下标”的关系

你可以把它总结成一句很重要的话:

在表头和数据行中,同一列的数据,永远有相同的下标。

比如表头第 2 列是 NAME,那每行第 2 列就是名字。
表头第 1 列是 MARKS,那每行第 1 列就是分数。

所以:

marks_index = columns.index('MARKS')

找到的是“分数列的下标”。

而:

row[marks_index]

取到的就是“这一行分数列上的值”。


手动模拟一遍,你就会彻底明白

情况 1:表头是 ID MARKS NAME CLASS

输入:

ID MARKS NAME CLASS
1 97 Raymond 7

拆开后:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']
row = ['1', '97', 'Raymond', '7']

先找:

marks_index = columns.index('MARKS')

因为 'MARKS' 在下标 1,所以:

marks_index = 1

然后:

row[marks_index]

就变成:

row[1]

得到:

'97'

这就是分数。


情况 2:表头顺序变了

输入变成:

MARKS CLASS NAME ID
92 2 Calum 1

拆开后:

columns = ['MARKS', 'CLASS', 'NAME', 'ID']
row = ['92', '2', 'Calum', '1']

这时候:

marks_index = columns.index('MARKS')

得到:

marks_index = 0

因为 MARKS 在第 0 个位置。

接着:

row[marks_index]

就等于:

row[0]

得到:

'92'

还是正确取到了分数。


情况 3:MARKS 在最后一列

如果表头是:

ID NAME CLASS MARKS

某一行是:

1 Raymond 7 97

拆开后:

columns = ['ID', 'NAME', 'CLASS', 'MARKS']
row = ['1', 'Raymond', '7', '97']

这时:

marks_index = columns.index('MARKS')

得到:

marks_index = 3

于是:

row[marks_index]

就等于:

row[3]

得到:

'97'

依然正确。


你可以把它理解成“表头是地图,数据行是内容”

这是一个很好记的比喻。

表头 columns 是地图

它负责告诉你:

  • 第 0 列是什么
  • 第 1 列是什么
  • 第 2 列是什么
  • 第 3 列是什么

数据行 row 是具体内容

它负责告诉你:

  • 第 0 列放了什么值
  • 第 1 列放了什么值
  • 第 2 列放了什么值
  • 第 3 列放了什么值

所以表头里你一旦查出:

MARKS 在第 1 列

那么数据行里你就知道:

第 1 列放的就是分数

于是自然就可以写:

row[marks_index]

为什么不能直接写 row['MARKS']

因为 row 也是一个列表,不是字典。

比如:

row = ['1', '97', 'Raymond', '7']

列表只能用数字下标取值:

row[0]
row[1]
row[2]

不能写成:

row['MARKS']

因为 'MARKS' 不是列表下标。

所以必须分成两步:

第一步,先在表头中找出 MARKS 的数字位置:

marks_index = columns.index('MARKS')

第二步,再用这个数字位置去数据行中取值:

row[marks_index]

为什么这一步特别适合初学者记成固定模板

因为以后你会遇到很多类似题:

  • NAME 对应的数据
  • ID 对应的数据
  • AGE 对应的数据
  • SCORE 对应的数据

这种题的模板完全一样:

target_index = columns.index('目标列名')
value = row[target_index]

你要把它记成一对固定搭档:

columns.index(...)
row[...]

前者负责找“位置”,后者负责按位置“拿值”。


这其实就是“先定位,再取值”

整套逻辑可以压缩成四个字:

先定位,再取值。

详细一点就是:

  1. 用表头定位 MARKS 在第几列
  2. 用同样的列号去每一行取出对应的数据

所以:

marks_index = columns.index('MARKS')

是“定位”。

而:

row[marks_index]

是“取值”。

这两句必须连起来理解,不能分开死记。


最容易出错的几个误区

误区 1:以为 row[marks_index] 是自动识别“分数”

不是自动识别。

Python 根本不知道哪个值是分数,它只是按下标取值。

真正让它“取到分数”的原因是:

你前面已经通过表头,算出了 MARKS 所在的下标。


误区 2:以为每一行数据顺序可以乱

不可以。

表头顺序可以变,但一旦表头确定了,下面每一行数据就必须按那个顺序来。

否则整个表就没有意义了。


误区 3:以为 marks_index 每一行都要重新算一次

不需要。

表头只读一次,所以 MARKS 的列位置也只要找一次。

后面每一行都沿用这个位置就行。

比如表头一旦确定 MARKS 在下标 1,那么所有学生行的下标 1 都是分数。


用最简短的一句话总结

为什么 row[marks_index] 能刚好取到每一行对应的分数?

因为:

marks_index 记录的是 “MARKS 这一列的列号”,而每一行数据都和表头按相同列顺序对齐,所以用这个列号去取,拿到的自然就是分数。


再给你一个非常值得记住的图

你以后可以在脑子里默认画成这样:

下标0123
表头 columnsIDMARKSNAMECLASS
数据 row197Raymond7

只要你知道 MARKS 在下标 1,那么同一列下面的数据 97 也必然在下标 1。

所以:

row[1]

就是分数。

row[marks_index] 只是把这个 1 写得更灵活、更通用而已。


小练习

已知:

columns = ['CLASS', 'NAME', 'MARKS', 'ID']
row = ['7', 'Raymond', '97', '1']

请你自己先想一想:

  1. marks_index 等于几
  2. row[marks_index] 得到什么
  3. 为什么它刚好是分数

提示

先看 MARKS 在表头的哪个位置,再去同样的位置看 row

如果你愿意,我下一步可以继续补一节:

为什么 columnsrow 虽然都是 split() 得到的列表,但一个是“字段名列表”,一个是“字段值列表”。

为什么 columnsrow 虽然都是 split() 得到的列表,但一个是“字段名列表”,一个是“字段值列表”

这个问题问得很好。

因为从代码表面看,它们确实很像:

columns = input().split()
row = input().split()

两句长得几乎一模一样,都是:

  • input() 读一整行
  • split() 按空格拆开
  • 得到一个列表

所以很多初学者会觉得:

“既然写法一样,那它们不就是同一种东西吗?”

写法一样,但含义不一样。

这正是你现在要彻底搞清楚的地方。


先说最核心的结论

split() 只负责做一件事:

把一整行字符串拆成若干个小字符串,并放进列表里。

它并不会自动判断:

  • 这些字符串是列名
  • 还是学生数据
  • 还是命令
  • 还是数字
  • 还是别的内容

所以,split() 只是一个“拆分工具”。

至于拆出来的列表到底代表什么,不是由 split() 决定的,而是由:

这一行输入本身的内容和它在题目中的位置

来决定的。


先理解:同样的工具,可以处理不同性质的内容

这和剪刀很像。

剪刀可以剪纸,也可以剪布。
虽然工具是同一个,但你剪的材料不同,结果的意义就不同。

split() 也一样。

它可以拆:

  • 表头这一行
  • 学生数据这一行
  • 命令这一行
  • 数字这一行

虽然都是“拆开成列表”,但拆开的内容身份不一样。


为什么 columns 是“字段名列表”

来看题目的第二行。

题目说,第二行包含列名,也就是:

  • ID
  • MARKS
  • NAME
  • CLASS

只是顺序可能变化。

例如输入可能是:

ID MARKS NAME CLASS

执行:

columns = input().split()

之后得到:

['ID', 'MARKS', 'NAME', 'CLASS']

你会发现,这个列表里的元素,不是具体某个学生的数据,而是:

每一列的名字。

所以 columns 的作用不是存数据内容,而是告诉你:

  • 第 0 列是什么
  • 第 1 列是什么
  • 第 2 列是什么
  • 第 3 列是什么

因此它叫“字段名列表”最合适。

这里的“字段名”,你可以理解成“列标题”“列标签”。


为什么 row 是“字段值列表”

接着看后面的某一行学生数据。

比如:

1 97 Raymond 7

执行:

row = input().split()

之后得到:

['1', '97', 'Raymond', '7']

这个列表里放的就不是列名了,而是某一个学生在各列上的具体内容

  • 1 是这个学生的 ID
  • 97 是这个学生的 MARKS
  • Raymond 是这个学生的 NAME
  • 7 是这个学生的 CLASS

所以,row 存放的是:

这一行每个字段对应的实际值。

因此它是“字段值列表”。


两者的区别,不在代码写法,而在“这一行代表什么”

这是你必须建立起来的思维方式。

下面这两句代码:

columns = input().split()
row = input().split()

虽然写法很像,但本质区别不在 split(),而在于:

第一行输入代表的是表头

所以拆出来的是字段名列表:

['ID', 'MARKS', 'NAME', 'CLASS']

第二行输入代表的是某个学生的数据

所以拆出来的是字段值列表:

['1', '97', 'Raymond', '7']

也就是说:

同样是“拆成列表”,但拆出来的那一行本来就不是一类信息。


用“表格”去理解会特别清楚

你可以把整个输入想成一个表格。

比如:

IDMARKSNAMECLASS
197Raymond7
250Steven4
391Adrian9

在这个表格里:

第一行是列标题

也就是:

| ID | MARKS | NAME | CLASS |

它描述的是:

“每一列叫什么名字。”

这对应:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']

后面的每一行是具体记录

例如:

| 1 | 97 | Raymond | 7 |

它描述的是:

“某一个学生在这些列上的具体值是什么。”

这对应:

row = ['1', '97', 'Raymond', '7']

所以你会发现:

  • columns 是这张表的“说明”
  • row 是这张表的“内容”

为什么这两个列表必须分开理解

因为它们在程序里的用途完全不一样。

columns 的用途:负责定位

你会拿它去做:

marks_index = columns.index('MARKS')

也就是说,columns 不是拿来算总分的,而是拿来查:

哪一列是 MARKS

它更像“地图”。


row 的用途:负责取值

你会拿它去做:

row[marks_index]

也就是说,row 不是拿来查列名的,而是拿来取:

这一行在某一列上的具体值

它更像“数据”。


可以把它们记成“名字层”和“值层”

这是一个很实用的理解方式。

columns:名字层

这里存的是字段名:

  • ID
  • MARKS
  • NAME
  • CLASS

row:值层

这里存的是字段值:

  • 1
  • 97
  • Raymond
  • 7

所以整个程序其实是在做两层配对:

名字层 columns值层 row
ID1
MARKS97
NAMERaymond
CLASS7

程序先在名字层找到:

'MARKS'

的位置,再去值层取同样位置上的数据:

'97'

split() 并不会帮你区分“名字”和“值”

这一点很重要。

split() 只是机械地把一行拆开。

例如:

'ID MARKS NAME CLASS'.split()

得到:

['ID', 'MARKS', 'NAME', 'CLASS']

而:

'1 97 Raymond 7'.split()

得到:

['1', '97', 'Raymond', '7']

你会发现,split() 完全没有“思考”,它只是把空格当成分隔符去切。

所以:

  • 之所以第一个列表叫字段名列表,是因为原字符串本来就是表头
  • 之所以第二个列表叫字段值列表,是因为原字符串本来就是数据行

身份来自输入内容本身,不来自 split()


这和变量名也有关系

虽然本质不是变量名决定的,但变量名会帮助你理解。

比如:

columns = input().split()

你看到 columns,就应该想到:

这是列名、列标题、表头。

而:

row = input().split()

你看到 row,就应该想到:

这是某一行的数据内容。

所以好的变量名,其实是在提醒你:

这两个列表虽然结构相似,但职责不同。


结构相同,不代表语义相同

这是编程里很常见的一种情况。

比如下面两个列表:

['apple', 'banana', 'orange']
['Tom', '18', 'male']

它们都是列表,结构形式一样。
但第一个是水果列表,第二个是个人信息列表。

所以“长得一样”不代表“意义一样”。

在这道题里也是一样:

columns = ['ID', 'MARKS', 'NAME', 'CLASS']
row = ['1', '97', 'Raymond', '7']

它们都是列表,但一个表示字段名,一个表示字段值。


为什么这一步理解清楚之后,后面的代码就顺了

只要你明白了:

  • columns 是列名列表
  • row 是当前这一行的数据列表

你就会很自然地理解下面这两句:

marks_index = columns.index('MARKS')
total += int(row[marks_index])

第一句是在“列名列表”里找:

MARKS 这个名字在第几列

第二句是在“数据列表”里取:

这一行第几列的实际值

这就完成了从“字段名”到“字段值”的映射。


你可以把它理解成“说明书”和“实际内容”

这个比喻也很好记。

columns 是说明书

它告诉你:

  • 第 0 个位置表示什么
  • 第 1 个位置表示什么
  • 第 2 个位置表示什么

row 是实际内容

它告诉你:

  • 第 0 个位置放了什么值
  • 第 1 个位置放了什么值
  • 第 2 个位置放了什么值

于是程序的思路就是:

先看说明书,找到 MARKS 在第几个位置
再去实际内容里取那个位置上的值


最后把三者关系连起来

现在你可以把这三样东西放在一起理解:

1. columns

字段名列表,负责说明每列是什么。

['ID', 'MARKS', 'NAME', 'CLASS']

2. marks_index

从字段名列表里查出来的列号。

1

3. row

字段值列表,负责提供某一行的实际数据。

['1', '97', 'Raymond', '7']

于是:

row[marks_index]

就是:

row[1]

得到:

'97'

这就是该学生的分数。


一句最值得记住的话

请把这一句记牢:

columns 存的是“这列叫什么”,row 存的是“这一列的值是什么”。

两者都是 split() 得到的列表,但一个负责描述结构,一个负责承载数据。


小练习

已知输入如下:

NAME ID CLASS MARKS
Tom 1 5 88

请你自己先想一想:

  1. columns 会变成什么
  2. row 会变成什么
  3. columns 里哪个元素表示“分数字段”
  4. row 里哪个元素表示“Tom 的分数”

提示

先区分“列名”和“列值”,再去看它们是否处在同一个下标位置。

文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇