从文件读取时一次创建2个列表,pythonically
我正在读一个大文件,里面有数十万个数字对代表一个图形的边。我想在运行过程中构建两个列表:一个是前向的,另一个是反向的 目前,我正在为循环执行显式的从文件读取时一次创建2个列表,pythonically,python,list,python-3.x,Python,List,Python 3.x,我正在读一个大文件,里面有数十万个数字对代表一个图形的边。我想在运行过程中构建两个列表:一个是前向的,另一个是反向的 目前,我正在为循环执行显式的,因为我需要对我读到的行进行一些预处理。然而,我想知道是否有一种更像Python的方法来构建这些列表,比如列表理解,等等 但是,由于我有两个列表,我看不到一种方法可以在不读取两次文件的情况下使用理解来填充它们 我现在的代码是: with open('SCC.txt') as data: for line in data: lin
,因为我需要对我读到的行进行一些预处理。然而,我想知道是否有一种更像Python的方法来构建这些列表,比如列表理解,等等
但是,由于我有两个列表,我看不到一种方法可以在不读取两次文件的情况下使用理解来填充它们
我现在的代码是:
with open('SCC.txt') as data:
for line in data:
line = line.rstrip()
if line:
edge_list.append((int(line.rstrip().split()[0]), int(line.rstrip().split()[1])))
reversed_edge_list.append((int(line.rstrip().split()[1]), int(line.rstrip().split()[0])))
您不能在一个理解中创建两个列表,因此,与其对两个列表执行两次相同的操作,一个可行的选项是初始化其中一个列表,然后通过反转第一个列表中的每个条目来创建第二个列表。这样您就不会在文件上重复两次
为此,您可以创建具有理解力的第一个列表edge\u list
(不确定为什么再次调用rsplit
):
现在检查每个条目并用[::-1]
将其反转,以创建其反转的同级反转边缘列表
将模拟数据用于边缘\u列表
:
edge_list = [(1, 2), (3, 4), (5, 6)]
将其反转可能如下所示:
reverse_edge_list = [t[::-1] for t in edge_list]
现在看起来像:
reverse_edge_list
[(2, 1), (4, 3), (6, 5)]
我会保留您的逻辑,因为它是Pythonic方法,只是不会多次拆分/rstrip同一行:
with open('SCC.txt') as data:
for line in data:
spl = line.split()
if spl:
i, j = map(int, spl)
edge_list.append((i, j))
reversed_edge_list.append((j, i))
在已经调用rstrip的情况下调用它本身是多余的,在进行拆分时更是如此,因为这已经删除了空格,所以只拆分一次就意味着可以省去很多不必要的工作
您还可以使用csv.reader读取数据,并在使用单个空格分隔后过滤空行:
from csv import reader
with open('SCC.txt') as data:
edge_list, reversed_edge_list = [], []
for i, j in filter(None, reader(data, delimiter=" ")):
i, j = int(i), int(j)
edge_list.append((i, j))
reversed_edge_list.append((j, i))
或者,如果有多个空格分隔,您可以使用映射(str.split,data)
:
无论您选择什么,都比两次查看数据或多次拆分同一行要快。可能不清楚,但更短:
with open('SCC.txt') as data:
process_line = lambda line, r: (int(line.rstrip().split()[r]), int(line.rstrip().split()[1-r]))
edge_list, reverved_edge_list = map(list, zip(*[(process_line(line, 0), process_line(line, 1))
for line in data
if line.rstrip()]))
这里有一个解决办法
测试文件:
In[19]: f = ["{} {}".format(i,j) for i,j in zip(xrange(10), xrange(10, 20))]
In[20]: f
Out[20]:
['0 10',
'1 11',
'2 12',
'3 13',
'4 14',
'5 15',
'6 16',
'7 17',
'8 18',
'9 19']
一个使用理解、压缩和映射的班轮:
In[27]: l, l2 = map(list,zip(*[(tuple(map(int, x.split())), tuple(map(int, x.split()))[::-1]) for x in f]))
In[28]: l
Out[28]:
[(0, 10),
(1, 11),
(2, 12),
(3, 13),
(4, 14),
(5, 15),
(6, 16),
(7, 17),
(8, 18),
(9, 19)]
In[29]: l2
Out[29]:
[(10, 0),
(11, 1),
(12, 2),
(13, 3),
(14, 4),
(15, 5),
(16, 6),
(17, 7),
(18, 8),
(19, 9)]
解释一下,通过[(tuple(map(int,x.split())))、tuple(map(int,x.split())[::-1])for x in f]
我们构建了一个包含成对元组的列表,其中包含成对元组及其反向形式:
In[24]: [(tuple(map(int, x.split())), tuple(map(int, x.split()))[::-1]) for x in f]
Out[24]:
[((0, 10), (10, 0)),
((1, 11), (11, 1)),
((2, 12), (12, 2)),
((3, 13), (13, 3)),
((4, 14), (14, 4)),
((5, 15), (15, 5)),
((6, 16), (16, 6)),
((7, 17), (17, 7)),
((8, 18), (18, 8)),
((9, 19), (19, 9))]
将zip
应用到解包表单中,我们在主元组中拆分元组,因此我们有两个元组,第一个元组包含元组对,另一个元组包含相反的元组对:
In[25]: zip(*[(tuple(map(int, x.split())), tuple(map(int, x.split()))[::-1]) for x in f])
Out[25]:
[((0, 10),
(1, 11),
(2, 12),
(3, 13),
(4, 14),
(5, 15),
(6, 16),
(7, 17),
(8, 18),
(9, 19)),
((10, 0),
(11, 1),
(12, 2),
(13, 3),
(14, 4),
(15, 5),
(16, 6),
(17, 7),
(18, 8),
(19, 9))]
差不多了,我们只是使用map
将元组转换为列表
编辑:
正如@PadraicCunningham所问的,要过滤空行,只需在理解中添加一个if x
[…for x in f if x]
我可能建议[元组(map(line.split())…]
看起来有点干净。用一个空行文件试试。用filter或在comprehension@PadraicCunninghamhey中过滤空行。我不知道你的答案,我自己也是这样做的,+1我实际上在做rstrip()
来删除空行中的尾随\r\n
字符。如果没有它,您的代码就会错误地显示为i,j=map(int,spl)ValueError:没有足够的值来解包(预期为2,得到0)
@NickSlavsky,这本应该是,如果spl
,则任何只有空格的行的spl都将为空,我自己没有弄明白。非常感谢。顺便说一句,您的解决方案的速度几乎是我的初始代码的2倍。
In[24]: [(tuple(map(int, x.split())), tuple(map(int, x.split()))[::-1]) for x in f]
Out[24]:
[((0, 10), (10, 0)),
((1, 11), (11, 1)),
((2, 12), (12, 2)),
((3, 13), (13, 3)),
((4, 14), (14, 4)),
((5, 15), (15, 5)),
((6, 16), (16, 6)),
((7, 17), (17, 7)),
((8, 18), (18, 8)),
((9, 19), (19, 9))]
In[25]: zip(*[(tuple(map(int, x.split())), tuple(map(int, x.split()))[::-1]) for x in f])
Out[25]:
[((0, 10),
(1, 11),
(2, 12),
(3, 13),
(4, 14),
(5, 15),
(6, 16),
(7, 17),
(8, 18),
(9, 19)),
((10, 0),
(11, 1),
(12, 2),
(13, 3),
(14, 4),
(15, 5),
(16, 6),
(17, 7),
(18, 8),
(19, 9))]