基于子字符串拆分列表

时间:2018-02-03 21:57:07

标签: python string python-3.x list nested-lists

我有以下列表:

['1(Reg)', '100', '103', '102', '100', '2(Reg)', '98', '101', '100', '3(Reg)', '96', '99', '98', '4(Reg)', '100', '100', '100', '100', '5(Reg)', '98', '99', '99', '100', '6(Reg)', '99.47', '99.86', '99.67', '100']

我想将此列表拆分为多个列表,以便每个子列表都有子串“(Reg)”出现一次:

[['1(Reg)', '100', '103', '102', '100'],
['2(Reg)', '98', '101', '100'],
['3(Reg)', '96', '99', '98'],
['4(Reg)', '100', '100', '100', '100'],
['5(Reg)', '98', '99', '99', '100'],
['6(Reg)', '99.47', '99.86', '99.67', '100']]

我尝试使用分隔符加入列表并将其拆分为(Reg),但这不起作用。如何将列表拆分为上面的嵌套列表?

8 个答案:

答案 0 :(得分:5)

WVO答案略有不同(优化)版本:

splitted = []

for item in l:
    if '(Reg)' in item:
        splitted.append([])
    splitted[-1].append(item)

#[['1(Reg)', '100', '103', '102', '100'], ['2(Reg)', '98', '101', '100'], 
# ['3(Reg)', '96', '99', '98'], ['4(Reg)', '100', '100', '100', '100'], 
# ['5(Reg)', '98', '99', '99', '100'], 
# ['6(Reg)', '99.47', '99.86', '99.67', '100']]

答案 1 :(得分:5)

您可以将itertools.groupby与正则表达式一起使用:

import itertools
import re
s = ['1(Reg)', '100', '103', '102', '100', '2(Reg)', '98', '101', '100', '3(Reg)', '96', '99', '98', '4(Reg)', '100', '100', '100', '100', '5(Reg)', '98', '99', '99', '100', '6(Reg)', '99.47', '99.86', '99.67', '100']
new_data = [list(b) for _, b in itertools.groupby(s, key=lambda x:bool(re.findall('\d+\(', x)))]
final_data = [new_data[i]+new_data[i+1] for i in range(0, len(new_data), 2)]

输出:

[['1(Reg)', '100', '103', '102', '100'], 
 ['2(Reg)', '98', '101', '100'], 
 ['3(Reg)', '96', '99', '98'], 
 ['4(Reg)', '100', '100', '100', '100'], 
 ['5(Reg)', '98', '99', '99', '100'], 
 ['6(Reg)', '99.47', '99.86', '99.67', '100']]

答案 2 :(得分:5)

这是一种方式,但不一定是最佳方式:

from itertools import zip_longest

lst = ['1(Reg)', '100', '103', '102', '100', '2(Reg)', '98', '101', '100',
       '3(Reg)', '96', '99', '98', '4(Reg)', '100', '100', '100', '100',
       '5(Reg)', '98', '99', '99', '100', '6(Reg)', '99.47', '99.86', '99.67', '100']

indices = [i for i, j in enumerate(lst) if '(Reg)' in j]
lst_new = [lst[i:j] for i, j in zip_longest(indices, indices[1:])]

# [['1(Reg)', '100', '103', '102', '100'],
#  ['2(Reg)', '98', '101', '100'],
#  ['3(Reg)', '96', '99', '98'],
#  ['4(Reg)', '100', '100', '100', '100'],
#  ['5(Reg)', '98', '99', '99', '100'],
#  ['6(Reg)', '99.47', '99.86', '99.67', '100']]

答案 3 :(得分:4)

好的,这是我对超简单标准列表理解的看法(非常类似于@ jp_data_analysis'答案):

>>> from pprint import pprint
>>> d = ['1(Reg)', '100', '103', '102', '100', '2(Reg)', '98', '101', '100', '3(Reg)', '96', '99', '98', '4(Reg)', '100', '100', '100', '100', '5(Reg)', '98', '99', '99', '100', '6(Reg)', '99.47', '99.86', '99.67', '100']
>>> idx = filter(lambda i: d[i].endswith("(Reg)"), range(len(d))) + [len(d)]
>>> idx
[0, 5, 9, 13, 18, 23, 28]
>>> res = [d[idx[i-1]:idx[i]] for i in range(1,len(idx))]
>>> pprint(res)
[['1(Reg)', '100', '103', '102', '100'],
 ['2(Reg)', '98', '101', '100'],
 ['3(Reg)', '96', '99', '98'],
 ['4(Reg)', '100', '100', '100', '100'],
 ['5(Reg)', '98', '99', '99', '100'],
 ['6(Reg)', '99.47', '99.86', '99.67', '100']]

说明:idx保存以(Reg)结尾的每个元素的索引(包括列表长度作为最终元素)。然后通过这些元素之间的间隔定义列表res

在哲学上注意:每当你遇到这样的问题时,问问自己:我是怎么来到这里的?为什么我需要处理一些超脆弱的隐式字符串格式规则而不是真正的数据结构?考虑到间隔和数据层次结构的问题?通过设计强制执行限制并允许简单查询的一个? 在推特上找人责备并咆哮他们:)

答案 4 :(得分:2)

我们可以使用for循环并使用两个列表:我们用于构建当前行的列表之一,其他列表存储我们当前拥有的所有行。像:

rows = []
row = []
for word in data:
    if '(Reg)' in word:
        rows.append(row)
        row = []
    row.append(word)
rows.append(row)

使用data字符串的初始列表。

然而,这有一个问题:首先会添加一个空行(假设第一个元素中有(Reg)。我们可以通过仅添加非空row来阻止这种情况,例如:

rows = []
row = []
for word in data:
    if '(Reg)' in word:
        if row:
            rows.append(row)
        row = []
    row.append(word)
if row:
    rows.append(row)

我们可以将上述内容概括为专用函数:

split_at(data, predicate, with_empty=False):
    rows = []
    row = []
    for word in data:
        if predicate(word):
            if with_empty or row:
                rows.append(row)
            row = []
        row.append(word)
    if with_empty or row:
        rows.append(row)
    return rows

然后我们可以这样称呼它:

split_at(our_list, lambda x: '(Reg)' in x)

答案 5 :(得分:2)

使用itertools.groupby

lst = ['1(Reg)', '100', '103', '102', '100', '2(Reg)', '98', '101', '100', '3(Reg)', '96', '99', '98', '4(Reg)', '100', '100', '100', '100', '5(Reg)', '98', '99', '99', '100', '6(Reg)', '99.47', '99.86', '99.67', '100']
from itertools import groupby
[a+b for a,b in zip(*([iter(list(g) for k, g in groupby(lst, lambda x:'Reg' in x))]*2))]

输出:

[['1(Reg)', '100', '103', '102', '100'],
 ['2(Reg)', '98', '101', '100'],
 ['3(Reg)', '96', '99', '98'],
 ['4(Reg)', '100', '100', '100', '100'],
 ['5(Reg)', '98', '99', '99', '100'],
 ['6(Reg)', '99.47', '99.86', '99.67', '100']]

答案 6 :(得分:2)

这是没有库的另一种方式。这是一个基于DYZ答案的列表理解:

w = []
[w.append([]) or w[-1].append(e) if '(Reg)' in e else w[-1].append(e) for e in data]

答案 7 :(得分:1)

你也可以试试这个:

from itertools import groupby

lst = ['1(Reg)', '100', '103', '102', '100', '2(Reg)', '98', '101', '100',
       '3(Reg)', '96', '99', '98', '4(Reg)', '100', '100', '100', '100',
       '5(Reg)', '98', '99', '99', '100', '6(Reg)', '99.47', '99.86', '99.67', '100']

grouped = [list(g) for k, g in groupby(lst, key = lambda x: x.endswith('(Reg)'))]

result = [x + y for x, y in zip(grouped[0::2], grouped[1::2])]

print(result)

哪个输出:

[['1(Reg)', '100', '103', '102', '100'], ['2(Reg)', '98', '101', '100'], ['3(Reg)', '96', '99', '98'], ['4(Reg)', '100', '100', '100', '100'], ['5(Reg)', '98', '99', '99', '100'], ['6(Reg)', '99.47', '99.86', '99.67', '100']]