如何在不在Python中创建中间列表的情况下拆分字符串并重新加入?

Tom*_*Tom 9 python string iterator generator

说我有以下内容:

dest = "\n".join( [line for line in src.split("\n") if line[:1]!="#"] )
Run Code Online (Sandbox Code Playgroud)

(即从多行字符串中删除以#开头的所有行src)

src是非常大的,所以我假设.split()将创建一个大的中间列表.我可以将列表理解更改为生成器表达式,但是我可以使用某种"xsplit"一次只能在一行上工作吗?我的假设是否正确?处理这个问题的最有效(内存)方法是什么?

澄清:这是由于我的代码内存不足造成的.我知道有一些方法可以完全重写我的代码来解决这个问题,但问题是关于Python:是否有一个版本的split()(或一个等效的习惯用法),它的行为类似于生成器,因此无法进行额外的工作副本src

Mat*_*hen 5

buffer = StringIO(src)
dest = "".join(line for line in buffer if line[:1]!="#")
Run Code Online (Sandbox Code Playgroud)

当然,如果你StringIO全程使用,这真的是最有意义的.它的工作方式与文件大致相同.您可以搜索,读取,写入,迭代(如图所示)等.


Joh*_*ooy 5

这是使用itertools进行常规拆分的一种方法

>>> import itertools as it
>>> src="hello\n#foo\n#bar\n#baz\nworld\n"
>>> line_gen = (''.join(j) for i,j in it.groupby(src, "\n".__ne__) if i)
>>> '\n'.join(s for s in line_gen if s[0]!="#")
'hello\nworld'
Run Code Online (Sandbox Code Playgroud)

groupby分别处理src中的每个char,因此性能可能不是很好,但它确实避免创建任何中间的大型数据结构

可能更好地花几行并制造发电机

>>> src="hello\n#foo\n#bar\n#baz\nworld\n"
>>>
>>> def isplit(s, t): # iterator to split string s at character t
...     i=j=0
...     while True:
...         try:
...             j = s.index(t, i)
...         except ValueError:
...             if i<len(s):
...                 yield s[i:]
...             raise StopIteration
...         yield s[i:j]
...         i = j+1
...
>>> '\n'.join(x for x in isplit(src, '\n') if x[0]!='#')
'hello\nworld'
Run Code Online (Sandbox Code Playgroud)

re有一个叫做的方法finditer,也可以用于此目的

>>> import re
>>> src="hello\n#foo\n#bar\n#baz\nworld\n"
>>> line_gen = (m.group(1) for m in re.finditer("(.*?)(\n|$)",src))
>>> '\n'.join(s for s in line_gen if not s.startswith("#"))
'hello\nworld'
Run Code Online (Sandbox Code Playgroud)

比较性能是OP尝试实际数据的练习