【问题标题】:How to read a file into multiple lists如何将文件读入多个列表
【发布时间】:2015-01-27 06:30:36
【问题描述】:

我正在做一个项目,我需要从文本文件(名为marks.txt)中读取行并将值放入列表中。该文件是有组织的,因此只需读取每一行并将其按顺序添加到 5 个列表中的每一个中,然后重复直到文件末尾。我环顾四周,尽管有一对看起来很有希望的夫妇,但还是找不到 Ineeed。 This one 有正确的想法,但仅适用于单个列表,this one 似乎是答案,但它比我可以使用或理解的方式更先进。最后,我找到了this one,它非常接近,我尝试按照答案 3 的方式做一些事情(与我几年前学到的类似,但它确实对我有用。如果有人对如何我可以将这些示例的圆顶应用到我的工作中,这将非常出色。对于这个项目,它不必是高效的,就使用的元素而言,它只是工作和简单。这就是我现在所拥有的:

studentName= mark1=mark2= mark3=mark4 = []
dataFile=open(dataFileRaw, "r")
for line in dataFile:
    studentName.append(line) #line 1 goes to array one, line 6 goes to array 1, second value, etc
    mark1.append(line) #line 2 goes to array two
    mark2.append(line) #line 3 goes to array three
    mark3.append(line) #line 4 goes to array four
    mark4.append(line) #line 5 goes to array five
dataFile.close()

【问题讨论】:

  • 为了清楚起见,我的 cmets 是我希望它的工作方式,而不是它目前的工作方式
  • 你当前的代码有什么问题?
  • 它产生 5 个列表,每个列表包含整个文件 5 次,而不是文件的 1/5
  • 我猜[如何在 Python 中克隆或复制列表?][1] 非常适合您的问题。 [1]:stackoverflow.com/questions/2612802/…
  • 该死,由于我的时间管理不好,不得不交出我的程序缺少一段代码,谢谢大家给出了彻底的答案。我希望我有时间来实施它们。明天我会整理它们并选择最好的。

标签: python file-io


【解决方案1】:

studentName= mark1=mark2= mark3=mark4 = [] 不会做你想做的事。它创建一个列表并将其绑定到多个名称。因此,如果您修改 studentName,修改将复制到 mark1、mark2 等。请参阅 List of lists changes reflected across sublists unexpectedly

但这里有一些使用列表列表的代码,可以正确收集您的数据。它使用.strip() 从每行数据中去除前导和尾随空格(包括换行符)。它还使用with 关键字,因此您无需显式关闭文件。

marks = [[] for _ in range(5)]

with open(dataFileRaw, "r") as dataFile:
    for i, line in enumerate(dataFile):
        marks[i % 5].append(line.strip())

enumerate() 是一个内置函数,它将一个可迭代对象作为其第一个参数,并将一个可选的起始编号作为其第二个参数。它返回一个新的可迭代对象,该对象产生成对的值(以元组的形式),对中的第一个值是一个计数,第二个值是原始可迭代对象的下一个元素。

来自help(enumerate)

enumerate(iterable[, start]) -> 用于索引的迭代器,可迭代的值

返回一个枚举对象。 iterable 必须是另一个对象 支持迭代。枚举对象产生包含一个 计数(从开始,默认为零)和产生的值 可迭代的论点。 enumerate 对于获取索引列表很有用:

(0, seq[0]), (1, seq[1]), (2, seq[2]), ...

看一些例子可能会有所帮助:

for i,c in enumerate('qwerty'):    
    print i, c

输出

0 q
1 w
2 e
3 r
4 t
5 y

我们还可以为enumerate() 提供start 参数,例如

seq = ['one', 'two', 'three']
for i, c in enumerate(seq, 1):
    print i, c

输出

1 one
2 two
3 three

% 运算符是模运算符。当我们将整数 a 除以整数 b 时,a % b 产生余数。例如,

for i in range(12):
    print i % 4

输出

0
1
2
3
0
1
2
3
0
1
2
3

%enumerate() 放在一起让我们可以做这样的事情:

for i, c in enumerate('_abcdefghij'):
    print i%5, c

输出

0 _
1 a
2 b
3 c
4 d
0 e
1 f
2 g
3 h
4 i
0 j

那么你现在明白什么了吗

for i, line in enumerate(dataFile):
    marks[i % 5].append(line.strip())

会吗?

【讨论】:

  • 您是否介意简要解释一下 i%5 在这种情况下的作用以及 enumerate(datafile) 的作用?
  • @qwerty22:是的,好的。请参阅我的答案的新增内容。
【解决方案2】:

这里的问题是您实际上并没有从 dataFileRaw 中读取数据,您只是使用 open() 实例化了文件。您必须确保通过以下方式从文件中读取所有数据:

dataFromFile = dataFile.read()

这会将所有数据作为字符串提取到 dataFile 变量中。关于这一点的好处是,之后,您可以通过在换行符 \n 处拆分来简单地将这个 dataFile 拆分为一个列表(当您在文本编辑器中按 Enter 时会自动添加)。

dataFromFile = dataFromFile.split("\n")[:-1]

我在末尾添加 [:-1] 的原因是因为如果您在文本文件中的每一行以 \n 结尾(如果您使用 enter,它会自动在文件中)它将导致最后一个元素列表为空,并且您不想处理此数据,因此 [:-1] 表示我们只对从索引 0(含)到最后一个元素(不含)的数据范围感兴趣。简单地说,我们删除了最后一个列表元素。

然后,您只需切换 for 循环以遍历 dataFromFile 而不是 dataFile。

【讨论】:

  • 对,所以我其实有文件打开部分,但是当我粘贴代码时忘记了
  • 啊,不。您可以使用类似for line in filehandle: 的方式逐行遍历打开的文件;每个line 都将保留行结束符。此外,通常最好逐行处理文本文件(如果可行),而不是将整个文件读入内存然后将其拆分为行。这样您就可以处理太大而无法放入内存的文件。
  • 哇。我已经做了2年以上的方法了,不知道你刚才提到的。谢谢指正!
【解决方案3】:

试试这个,这会从你的文件中创建一个行的元组,然后根据你的需要从元组中创建一个字符串列表:

lines = tuple(open("marks.txt", 'r'))
list1, list2, list3, list4, list5 = [], [], [], [], []
i, linesCount = 0, len(lines)

while (i < linesCount):
    list1.append(lines[i].rstrip())
    i += 1
    if (i < linesCount):
        list2.append(lines[i].rstrip())
        i += 1
    if (i < linesCount):
        list3.append(lines[i].rstrip())
        i += 1
    if (i < linesCount):
        list4.append(lines[i].rstrip())
        i += 1
    if (i < linesCount):
        list5.append(lines[i].rstrip())
        i += 1

print list1, list2, list3, list4, list5

【讨论】:

    【解决方案4】:

    答案

    s, g1, g2, g3, g4 = [[line.strip() for line in group_of_lines] for group_of_lines in zip(*zip(*[open('marks.txt')]*5))]
    

    我是如何得出答案的

    来自ipython shell 的提示:

    In [38]: cat marks.txt
    s1
    g11
    g12
    g13
    g14
    s2
    g21
    g22
    g23
    g24
    s3
    g31
    g32
    g33
    g34
    
    In [39]: zip(*[open('marks.txt')]*5)
    Out[39]: 
    [('s1\n', 'g11\n', 'g12\n', 'g13\n', 'g14\n'),
     ('s2\n', 'g21\n', 'g22\n', 'g23\n', 'g24\n'),
     ('s3\n', 'g31\n', 'g32\n', 'g33\n', 'g34\n')]
    
    In [40]: zip(*zip(*[open('marks.txt')]*5))
    Out[40]: 
    [('s1\n', 's2\n', 's3\n'),
     ('g11\n', 'g21\n', 'g31\n'),
     ('g12\n', 'g22\n', 'g32\n'),
     ('g13\n', 'g23\n', 'g33\n'),
     ('g14\n', 'g24\n', 'g34\n')]
    
    In [41]: [[line.strip() for line in group_of_lines] for group_of_lines in zip(*zip(*[open('marks.txt')]*5))]
    Out[41]: 
    [['s1', 's2', 's3'],
     ['g11', 'g21', 'g31'],
     ['g12', 'g22', 'g32'],
     ['g13', 'g23', 'g33'],
     ['g14', 'g24', 'g34']]
    
    In [42]: s, g1, g2, g3, g4 = [[line.strip() for line in group_of_lines] for group_of_lines in zip(*zip(*[open('marks.txt')]*5))]
    
    In [43]: print '\n'.join(map(str,(s,g1,g2,g3,g4)))
    ['s1', 's2', 's3']
    ['g11', 'g21', 'g31']
    ['g12', 'g22', 'g32']
    ['g13', 'g23', 'g33']
    ['g14', 'g24', 'g34']
    
    In [44]:
    

    逐行评论“我是如何得出答案的”

    [38]

    我个人版本的marks.txt 数据文件

    [39]

    程序的关键, grouper 程序无耻地改编自itertools模块fine docs

    文件对象可以简单理解为一个迭代器,它返回 文件内容一行一行,所以我们从一个包含 5 的列表开始 (相同的)文件迭代器的副本,它返回我们的内容 数据文件,并传递此列表的元素(通过使用 * 星号 运算符)到zip 内置函数,它返回一个元组列表 每个参数都有一个元素,例如:

    In [44]: zip(*[[1,2,3],[10,20,30]])
    Out[44]: [(1, 10), (2, 20), (3, 30)]
    

    因为zip 传递了同一文件的五个相同副本 迭代器,它构建一个包含前五行的元组列表, 我们文件的后五行,...。

    [40]

    但我们希望反过来!或者,换句话说,我们想要 转置我们的元组列表。

    序列序列的转置通常用 与我们刚刚看到的非常相似的成语......

    In [45]: zip(*[(1, 10), (2, 20), (3, 30)])
    Out[45]: [(1, 2, 3), (10, 20, 30)]
    

    [41]

    所有这些'\n' 换行符是怎么回事?让我们strip 他们走了……

    我们的问题是我们有一个双重嵌套,比如一个列表列表 包含我们要更正的元素...

    我们别无选择,只能用双循环解包元素,然后 然后将我们更正的、剥离的项目再次打包到一个列表中 列表...

    [42]

    我们有一个列表列表,其元素正是我们想要的 关联到我们的变量名,这可以使用一次扫描完成 什么叫_sequence unpacking...

    语句 42 代表了我们问题的紧凑解决方案。很长一段时间我们都知道 42 是答案,现在我们终于也知道了这个问题......

    [43]

    只是为了验证我们变量中的内容是我们的结果 正在寻找。

    【讨论】:

    • 在我看来,您试图对数据强加的数据结构是不合适的,那么以学生姓名为关键字的成绩列表字典怎么样? data={t[0].strip():[int(grad.strip()[1:]) for grad in t[1:]] for t in zip(*[open('marks.txt')]*5)}
    猜你喜欢
    • 1970-01-01
    • 2017-11-08
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 2011-03-17
    相关资源
    最近更新 更多