Python:每个数据块由可变数量的行组成,如何确定总块数?
Python: Each chunk of data consists of a variable amount of lines, how to determine the number of chunks total?
我有一个非常大的数据文件,每个条目看起来像这样:
5 (this can be any number, call this line n)
Line 1
Line 2
Line 3
n lines, in this case 5, i.e. lines 4 - 8
Line 9
n lines, in this case again 5, i.e. lines 10-14
Line 15
基本上,每个条目都以一行开头,然后是 3 行 + n 行 + 1 行 + n 行 + 1 行。
这个数字 n 是一个整数(但可能因条目而异)。有没有办法计算出我在这个文件中有多少数据条目?
我有一些代码,如果我知道有多少条目,那么我可以遍历每个条目...但是有没有办法首先计算出条目的数量?
谢谢!
编辑:这里是示例条目的两个示例 -
5
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
A -0.005364798 -0.022912843 0.017346957
B 0.527031905 0.603310150 0.560736787
B -0.629466850 -0.628385741 0.628048126
B -0.649090857 0.603667874 -0.726135880
B 0.683741908 -0.584386774 -0.700569743
-17.862057
-2.022841336 -1.477407454 -5.606136767
2.521789668 2.889251770 2.572440406
-0.401914888 -0.722582908 0.244151982
0.806040926 -0.990697574 1.474733506
-0.903074369 0.301436166 1.314862295
0.016462
7
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
A -0.591644968 -0.645755982 -0.014245979
B 1.198655655 -0.588872080 -0.025169784
B -1.460774580 -1.255848596 0.025804796
B 0.321839745 2.199107994 0.050450166
C 0.617684720 -1.389588077 -0.075897238
C 0.493712792 1.349385956 -0.004249822
D -0.808145644 0.577304796 0.014326943
-26.435922
1.649465696 -2.945456091 -0.152209323
0.531241391 -1.113956273 -0.135548573
-0.529287352 -0.556746737 -0.061346528
-2.152476371 6.326868481 0.441458459
-1.633473432 3.325310912 0.291306019
0.726490986 -8.268565793 -0.512575180
1.408090505 3.232545501 0.128915126
0.155658
第一个数字是一个整数(在这些示例中为 5 或 7),它决定了此条目之后的行数:
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
以及下一行之后的行数,在第一种情况下是:
-17.862057
每个条目看起来都像这样。基本上,目标是计算出总共有多少个条目,利用第一个整数给出剩余条目的总行数的概念。
我已经编写了这段代码来处理您给定的示例。它一开始并不知道有多少条目,但它只是不断地从文件中读取直到文件耗尽,以便提取每个条目。我已将您的示例输入保存在 input.txt
中。我现在还修改了代码以将数据读取为浮点数。
import pprint
import functools
#helper function for reading multiple lines
def read_n(in_file, n):
return [in_file.readline() for _ in range(n)]
#read one line of floats
def read_floats(line):
return list(map(float, line.split()))
#reads several lines of floats
def float_lines(lines):
return [read_floats(line) for line in lines]
def parse_entry(in_file):
#get n
n = in_file.readline().strip()
if n:
n = int(n)
#read 3, n, 1, n, 1 lines
head = float_lines(read_n(in_file, 3))
head_data = [(line[0], read_floats(line[1:])) for line in map(str.strip, read_n(in_file, n))]
mid = float(in_file.readline().strip())
tail_data = float_lines(read_n(in_file, n))
tail = float(in_file.readline().strip())
#readline to eat the empty line between entries
in_file.readline()
return n, head, head_data, mid, tail_data, tail
with open("input.txt", "r") as input_file:
#apply parse_entry until it stops returning
entries = list(iter(functools.partial(parse_entry, input_file), None))
print(len(entries))
pprint.pprint(entries)
输出:
2
[(5,
[[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
[('A', [-0.005364798, -0.022912843, 0.017346957]),
('B', [0.527031905, 0.60331015, 0.560736787]),
('B', [-0.62946685, -0.628385741, 0.628048126]),
('B', [-0.649090857, 0.603667874, -0.72613588]),
('B', [0.683741908, -0.584386774, -0.700569743])],
-17.862057,
[[-2.022841336, -1.477407454, -5.606136767],
[2.521789668, 2.88925177, 2.572440406],
[-0.401914888, -0.722582908, 0.244151982],
[0.806040926, -0.990697574, 1.474733506],
[-0.903074369, 0.301436166, 1.314862295]],
0.016462),
(7,
[[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
[('A', [-0.591644968, -0.645755982, -0.014245979]),
('B', [1.198655655, -0.58887208, -0.025169784]),
('B', [-1.46077458, -1.255848596, 0.025804796]),
('B', [0.321839745, 2.199107994, 0.050450166]),
('C', [0.61768472, -1.389588077, -0.075897238]),
('C', [0.493712792, 1.349385956, -0.004249822]),
('D', [-0.808145644, 0.577304796, 0.014326943])],
-26.435922,
[[1.649465696, -2.945456091, -0.152209323],
[0.531241391, -1.113956273, -0.135548573],
[-0.529287352, -0.556746737, -0.061346528],
[-2.152476371, 6.326868481, 0.441458459],
[-1.633473432, 3.325310912, 0.291306019],
[0.726490986, -8.268565793, -0.51257518],
[1.408090505, 3.232545501, 0.128915126]],
0.155658)]
表明它找到了 2 个条目,并将它们解析为浮点数,然后输出条目。我不完全确定条目是什么,所以我将它们命名为模棱两可的。请注意,我已经尽可能多地保留了我的大列表元组结构中条目的数据,因为我也不确定哪些位是相关的,所以原始文件几乎应该可以从内存中的条目中重建。
关于以字符开头的行 - 这是通过首先将 str.strip
应用到该行来实现的,因为有时在字符之前有一个 space。然后它将 line
分成 line[0]
和 line[1:]
,这是字符,以及代表数据的字符串切片,然后正常操作。
更多关于我如何将字符与浮点数分开的信息:
采取以下行:
A -0.005364798 -0.022912843 0.017346957
这将被解析:
head_data = [(line[0], read_floats(line[1:])) for line in map(str.strip, read_n(in_file, n))]
但是,如果我们只考虑这一行,我们可以少看一些表达式。该行发生的第一件事是 str.strip
,来自 map(str.strip..)
。这会去除任何尾随和前导的白色 space 以确保第一个字符是要删除的字母。这意味着内存中行的状态现在是:
"A -0.005364798 -0.022912843 0.017346957"
然后该行被分成line[0]
和read_floats(line[1:])
。这是区分字符串和浮点数的地方——字符串与字符串的其余部分分开,然后传递给 read_floats
。这是使用切片符号,一种强大的语法 Python 用于获取可迭代对象的子列表。切片 1:
表示 'slice from index 1 to the end of the string'。为清楚起见:
line[0] == "A"
line[1:] == " -0.005364798 -0.022912843 0.017346957"
for _
是一个 Python 约定,适用于您只需要重复某事而无需跟踪重复的内容。即它为 range(n)
中的每个数字读取一行,因此它读取 n
行,但它不需要跟踪当前行是哪个数字。它也可以说 for i in range(n)
,除了 i
不会被使用,因此迭代器被称为 _
以表明您不需要它。
if n:
检查字符串 n
是否不为空。这是因为当你 readline()
一个已经用完的文件时,返回一个空字符串。这意味着程序不会在处理完文件后崩溃,而是会巧妙地停止解析条目。这很重要,因为我们不知道条目的数量,所以我们一直尝试读取 n
直到我们无法再读取 n
,所以我们必须使用 if 语句。
关于为什么条目看起来如此复杂 - parse_entry(input_file)
只会解析一个条目。所有其他行李都需要解析所有条目。 functools.partial(parse_entry, input_file)
表示 'apply the argument input_file
to the function parse_entry
'。然后使用 iter
继续这样做,直到它 returns None
。这是一个非常有用的技巧 - iter 函数可以被赋予任何函数,然后是一个停止的值,它会一直从函数返回值,直到它达到 'stop' 值。一个更简单、更常见的例子可能是 iter(sys.stdin.readline, "a\n")
。这将继续读取 stdin
中的行,直到它遇到仅包含 a
.
的行
关于元组和元组解包 - 你可以这样做:
for n, head, head_data, mid, tail_data, tail in entries:
print("n is {}".format(n))
print("the first item of head_data is {}".format(head_data[0]))
for i in tail_data:
print("tail data item: {}".format(i))
这导致输出:
n is 5
the first item of head_data is ('A', [-0.005364798, -0.022912843, 0.017346957])
tail data item: [-2.022841336, -1.477407454, -5.606136767]
tail data item: [2.521789668, 2.88925177, 2.572440406]
tail data item: [-0.401914888, -0.722582908, 0.244151982]
tail data item: [0.806040926, -0.990697574, 1.474733506]
tail data item: [-0.903074369, 0.301436166, 1.314862295]
n is 7
the first item of head_data is ('A', [-0.591644968, -0.645755982, -0.014245979])
tail data item: [1.649465696, -2.945456091, -0.152209323]
tail data item: [0.531241391, -1.113956273, -0.135548573]
tail data item: [-0.529287352, -0.556746737, -0.061346528]
tail data item: [-2.152476371, 6.326868481, 0.441458459]
tail data item: [-1.633473432, 3.325310912, 0.291306019]
tail data item: [0.726490986, -8.268565793, -0.51257518]
tail data item: [1.408090505, 3.232545501, 0.128915126]
希望这向您展示了如何使用该结构。
我有一个非常大的数据文件,每个条目看起来像这样:
5 (this can be any number, call this line n)
Line 1
Line 2
Line 3
n lines, in this case 5, i.e. lines 4 - 8
Line 9
n lines, in this case again 5, i.e. lines 10-14
Line 15
基本上,每个条目都以一行开头,然后是 3 行 + n 行 + 1 行 + n 行 + 1 行。
这个数字 n 是一个整数(但可能因条目而异)。有没有办法计算出我在这个文件中有多少数据条目?
我有一些代码,如果我知道有多少条目,那么我可以遍历每个条目...但是有没有办法首先计算出条目的数量?
谢谢!
编辑:这里是示例条目的两个示例 -
5
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
A -0.005364798 -0.022912843 0.017346957
B 0.527031905 0.603310150 0.560736787
B -0.629466850 -0.628385741 0.628048126
B -0.649090857 0.603667874 -0.726135880
B 0.683741908 -0.584386774 -0.700569743
-17.862057
-2.022841336 -1.477407454 -5.606136767
2.521789668 2.889251770 2.572440406
-0.401914888 -0.722582908 0.244151982
0.806040926 -0.990697574 1.474733506
-0.903074369 0.301436166 1.314862295
0.016462
7
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
A -0.591644968 -0.645755982 -0.014245979
B 1.198655655 -0.588872080 -0.025169784
B -1.460774580 -1.255848596 0.025804796
B 0.321839745 2.199107994 0.050450166
C 0.617684720 -1.389588077 -0.075897238
C 0.493712792 1.349385956 -0.004249822
D -0.808145644 0.577304796 0.014326943
-26.435922
1.649465696 -2.945456091 -0.152209323
0.531241391 -1.113956273 -0.135548573
-0.529287352 -0.556746737 -0.061346528
-2.152476371 6.326868481 0.441458459
-1.633473432 3.325310912 0.291306019
0.726490986 -8.268565793 -0.512575180
1.408090505 3.232545501 0.128915126
0.155658
第一个数字是一个整数(在这些示例中为 5 或 7),它决定了此条目之后的行数:
10.0 0.0 0.0
0.0 10.0 0.0
0.0 0.0 10.0
以及下一行之后的行数,在第一种情况下是: -17.862057
每个条目看起来都像这样。基本上,目标是计算出总共有多少个条目,利用第一个整数给出剩余条目的总行数的概念。
我已经编写了这段代码来处理您给定的示例。它一开始并不知道有多少条目,但它只是不断地从文件中读取直到文件耗尽,以便提取每个条目。我已将您的示例输入保存在 input.txt
中。我现在还修改了代码以将数据读取为浮点数。
import pprint
import functools
#helper function for reading multiple lines
def read_n(in_file, n):
return [in_file.readline() for _ in range(n)]
#read one line of floats
def read_floats(line):
return list(map(float, line.split()))
#reads several lines of floats
def float_lines(lines):
return [read_floats(line) for line in lines]
def parse_entry(in_file):
#get n
n = in_file.readline().strip()
if n:
n = int(n)
#read 3, n, 1, n, 1 lines
head = float_lines(read_n(in_file, 3))
head_data = [(line[0], read_floats(line[1:])) for line in map(str.strip, read_n(in_file, n))]
mid = float(in_file.readline().strip())
tail_data = float_lines(read_n(in_file, n))
tail = float(in_file.readline().strip())
#readline to eat the empty line between entries
in_file.readline()
return n, head, head_data, mid, tail_data, tail
with open("input.txt", "r") as input_file:
#apply parse_entry until it stops returning
entries = list(iter(functools.partial(parse_entry, input_file), None))
print(len(entries))
pprint.pprint(entries)
输出:
2
[(5,
[[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
[('A', [-0.005364798, -0.022912843, 0.017346957]),
('B', [0.527031905, 0.60331015, 0.560736787]),
('B', [-0.62946685, -0.628385741, 0.628048126]),
('B', [-0.649090857, 0.603667874, -0.72613588]),
('B', [0.683741908, -0.584386774, -0.700569743])],
-17.862057,
[[-2.022841336, -1.477407454, -5.606136767],
[2.521789668, 2.88925177, 2.572440406],
[-0.401914888, -0.722582908, 0.244151982],
[0.806040926, -0.990697574, 1.474733506],
[-0.903074369, 0.301436166, 1.314862295]],
0.016462),
(7,
[[10.0, 0.0, 0.0], [0.0, 10.0, 0.0], [0.0, 0.0, 10.0]],
[('A', [-0.591644968, -0.645755982, -0.014245979]),
('B', [1.198655655, -0.58887208, -0.025169784]),
('B', [-1.46077458, -1.255848596, 0.025804796]),
('B', [0.321839745, 2.199107994, 0.050450166]),
('C', [0.61768472, -1.389588077, -0.075897238]),
('C', [0.493712792, 1.349385956, -0.004249822]),
('D', [-0.808145644, 0.577304796, 0.014326943])],
-26.435922,
[[1.649465696, -2.945456091, -0.152209323],
[0.531241391, -1.113956273, -0.135548573],
[-0.529287352, -0.556746737, -0.061346528],
[-2.152476371, 6.326868481, 0.441458459],
[-1.633473432, 3.325310912, 0.291306019],
[0.726490986, -8.268565793, -0.51257518],
[1.408090505, 3.232545501, 0.128915126]],
0.155658)]
表明它找到了 2 个条目,并将它们解析为浮点数,然后输出条目。我不完全确定条目是什么,所以我将它们命名为模棱两可的。请注意,我已经尽可能多地保留了我的大列表元组结构中条目的数据,因为我也不确定哪些位是相关的,所以原始文件几乎应该可以从内存中的条目中重建。
关于以字符开头的行 - 这是通过首先将 str.strip
应用到该行来实现的,因为有时在字符之前有一个 space。然后它将 line
分成 line[0]
和 line[1:]
,这是字符,以及代表数据的字符串切片,然后正常操作。
更多关于我如何将字符与浮点数分开的信息:
采取以下行:
A -0.005364798 -0.022912843 0.017346957
这将被解析:
head_data = [(line[0], read_floats(line[1:])) for line in map(str.strip, read_n(in_file, n))]
但是,如果我们只考虑这一行,我们可以少看一些表达式。该行发生的第一件事是 str.strip
,来自 map(str.strip..)
。这会去除任何尾随和前导的白色 space 以确保第一个字符是要删除的字母。这意味着内存中行的状态现在是:
"A -0.005364798 -0.022912843 0.017346957"
然后该行被分成line[0]
和read_floats(line[1:])
。这是区分字符串和浮点数的地方——字符串与字符串的其余部分分开,然后传递给 read_floats
。这是使用切片符号,一种强大的语法 Python 用于获取可迭代对象的子列表。切片 1:
表示 'slice from index 1 to the end of the string'。为清楚起见:
line[0] == "A"
line[1:] == " -0.005364798 -0.022912843 0.017346957"
for _
是一个 Python 约定,适用于您只需要重复某事而无需跟踪重复的内容。即它为 range(n)
中的每个数字读取一行,因此它读取 n
行,但它不需要跟踪当前行是哪个数字。它也可以说 for i in range(n)
,除了 i
不会被使用,因此迭代器被称为 _
以表明您不需要它。
if n:
检查字符串 n
是否不为空。这是因为当你 readline()
一个已经用完的文件时,返回一个空字符串。这意味着程序不会在处理完文件后崩溃,而是会巧妙地停止解析条目。这很重要,因为我们不知道条目的数量,所以我们一直尝试读取 n
直到我们无法再读取 n
,所以我们必须使用 if 语句。
关于为什么条目看起来如此复杂 - parse_entry(input_file)
只会解析一个条目。所有其他行李都需要解析所有条目。 functools.partial(parse_entry, input_file)
表示 'apply the argument input_file
to the function parse_entry
'。然后使用 iter
继续这样做,直到它 returns None
。这是一个非常有用的技巧 - iter 函数可以被赋予任何函数,然后是一个停止的值,它会一直从函数返回值,直到它达到 'stop' 值。一个更简单、更常见的例子可能是 iter(sys.stdin.readline, "a\n")
。这将继续读取 stdin
中的行,直到它遇到仅包含 a
.
关于元组和元组解包 - 你可以这样做:
for n, head, head_data, mid, tail_data, tail in entries:
print("n is {}".format(n))
print("the first item of head_data is {}".format(head_data[0]))
for i in tail_data:
print("tail data item: {}".format(i))
这导致输出:
n is 5
the first item of head_data is ('A', [-0.005364798, -0.022912843, 0.017346957])
tail data item: [-2.022841336, -1.477407454, -5.606136767]
tail data item: [2.521789668, 2.88925177, 2.572440406]
tail data item: [-0.401914888, -0.722582908, 0.244151982]
tail data item: [0.806040926, -0.990697574, 1.474733506]
tail data item: [-0.903074369, 0.301436166, 1.314862295]
n is 7
the first item of head_data is ('A', [-0.591644968, -0.645755982, -0.014245979])
tail data item: [1.649465696, -2.945456091, -0.152209323]
tail data item: [0.531241391, -1.113956273, -0.135548573]
tail data item: [-0.529287352, -0.556746737, -0.061346528]
tail data item: [-2.152476371, 6.326868481, 0.441458459]
tail data item: [-1.633473432, 3.325310912, 0.291306019]
tail data item: [0.726490986, -8.268565793, -0.51257518]
tail data item: [1.408090505, 3.232545501, 0.128915126]
希望这向您展示了如何使用该结构。