将每第n个字符串元素拆分并合并到数组中的最佳方法?

5 投票
2 回答
763 浏览
提问于 2025-04-18 01:31

抱歉标题有点模糊,但很难简洁地解释。

基本上,想象一下我在Python中有一个这样的列表:

['a', 'b', 'c\nd', 'e', 'f\ng', 'h', 'i']

从这个列表中,我想得到这个:

['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i']

我想到的一种方法是使用 reduce,像这样:

reduce(lambda x, y: x + y.split('\n'), lst, [])

但我觉得这样做效率不高,因为我们知道每隔几个元素就会有分隔符在里面。有没有什么建议呢?

补充说明:关于这个数组是怎么构建的,可能会影响问题。

我的文本格式是:

Ignorable line
Field name 1|Field name 2|Field name 3|Field name 4
Value 1|Value 2|Value 3|Value 4
Value 1|Value 2|Value 3|Value 4
...

在这里,我们可以有任意数量的字段名,并且每一行的字段名和数值数量是相等的。注意,数值中可能会有换行符。我们只知道它们会用 '|' 来分隔。所以我们可能会有:

Value 1|This is an long
value that extends over multiple
lines|Value 3|Value 4

我现在的做法是用 s.split('\n', 2) 来把字段名和数值分开,这样字段名会在一个字符串中,数值会在另一个字符串中。然后,当我用 '|' 来分割数值时,就得到了我最开始提到的那种列表形式。

2 个回答

2

过早的优化是万恶之源。

如果你真的因为这段代码遇到了性能问题,那是另一回事,但我怀疑你会有这样的情况。

当你进行优化时,往往会牺牲代码的可读性。如果是我,我会这样做:

list(itertools.chain(*[item.split() for item in lst]))

这样做会让你的意图非常清晰。

10

你可以直接用 ('\n'.join(lst)).split() 来得到第二个列表。

In [17]:

%timeit reduce(lambda x, y: x + y.split('\n'), lst, [])
100000 loops, best of 3: 9.64 µs per loop
In [18]:

%timeit ('\n'.join(lst)).split() 
1000000 loops, best of 3: 1.09 µs per loop

感谢 @Joran Beasley 提出的建议,使用 split() 而不是 split('\n')

编辑

现在我看到了你更新的问题,我觉得我们一开始就可以避免这种情况,看看这个(使用 re):

In [71]:

L=re.findall('([^|]+)\|',
           ''.join(['|'+item+'|' if item.count('|')==3 else item for item in S.split('\n')[1:]])+'|')
In [72]:

zip(*[L[i::4] for i in range(4)]) #4 being the number of fields.
Out[72]:
[('Field name 1', 'Field name 2', 'Field name 3', 'Field name 4'),
 ('Value 1', 'Value 2', 'Value 3', 'Value 4'),
 ('Value 1',
  'This is an longvalue that extends over multiplelines',
  'Value 3',
  'Value 4')]

这看起来像是一个最初为 SAS 准备的数据集,对吧?

撰写回答