根据可变字符串和可变块长度将列表拆分为子列表

split list into sublists according to variable string and variable block length

我有一个字符串列表:

['splitter001','stringA','stringB','splitter_1234','stringC']

我希望我的最终结果是:

[ ['splitter001','stringA','stringB'] , ['splitter_1234','stringC'] ]

拆分器分隔符不是相同的字符串。

如果元素索引 > 0,我尝试找到 'splitter',然后删除索引 [:2nd splitter] 并将第一组附加到新列表中,但这不会正常工作。

我在所有字符串上迭代一个 for 循环,它对第二组不起作用,所以我可以得到:

[ ['splitter001','stringA','stringB'] ] as my new list, but the second group is missing.

我已经阅读了很多关于这个主题的答案,最接近的解决方案是使用:

[list(x[1]) for x in itertools.groupby(myList, lambda x: x=='#') if not x[0]] 

但我不明白这种语法...我读过 groupby 和 intertools,但我不确定这对我的情况是否有帮助。

这是一种使用 for 循环的方法,正如您提到的那样,它可以处理第二组的情况:

# define list of strings for input
strings = ['splitter001','stringA','stringB','splitter_1234','stringC']
split_strings = []  # this is going to hold the final output
current_list = []  # this is a temporary list

# loop over strings in the input
for s in strings:
    if 'splitter' in s:
        # if current_list is not empty
        if current_list:
            split_strings.append(current_list)  # append to output
            current_list = []  # reset current_list
    current_list.append(s)

# outside of the loop, append the leftover strings (if any)
if current_list:
    split_strings.append(current_list)

这里的关键是你在循环之外的最后再做一个追加来捕获最后一组。

输出:

[['splitter001', 'stringA', 'stringB'], ['splitter_1234', 'stringC']]

编辑:添加代码说明。

我们创建一个临时变量 current_list 来保存我们将附加到最终输出 split_strings 的每个列表。

循环输入中的字符串。对于每个字符串 s,检查它是否包含 'splitter'。如果是并且 current_list 不为空,这意味着我们已经命中了下一个分隔符。将 current_list 附加到输出并将其清除,以便我们可以开始为下一组字符串收集项目。

检查后,将当前字符串附加到 current_list。这是可行的,因为我们在找到分隔符后将其清除(将其设置为等于 [])。

在列表的末尾,我们将剩余的内容附加到输出中(如果有的话)。

这是使用 groupby 执行此操作的一种方法。我们告诉 groupby 查找以 'splitter' 开头的字符串。这将创建两种类型的组:以 'splitter' 开头的字符串和所有其他字符串。例如,

from itertools import groupby

data = ['splitter001','stringA','stringB','splitter_1234','stringC']

for k, g in groupby(data, key=lambda s: s.startswith('splitter')):
    print(k, list(g))

输出

True ['splitter001']
False ['stringA', 'stringB']
True ['splitter_1234']
False ['stringC']

所以我们可以将这些组放入两个列表中,然后将它们压缩在一起以形成最终列表。

from itertools import groupby

data = ['splitter001','stringA','stringB','splitter_1234','stringC']

head = []
tail = []
for k, g in groupby(data, key=lambda s: s.startswith('splitter')):
    if k:
        head.append(list(g))
    else:
        tail.append(list(g))

out = [u+v for u, v in zip(head, tail)]
print(out)

输出

[['splitter001', 'stringA', 'stringB'], ['splitter_1234', 'stringC']]

这里有一个更紧凑的方法来做同样的事情,使用列表的列表来存储头列表和尾列表:

from itertools import groupby

data = ['splitter001','stringA','stringB','splitter_1234','stringC']
results = [[], []]
for k, g in groupby(data, key=lambda s: s.startswith('splitter')):
    results[k].append(list(g))

out = [v+u for u, v in zip(*results)]
print(out)

输出

[['splitter001', 'stringA', 'stringB'], ['splitter_1234', 'stringC']]

如果您想在单独的行上打印每个子列表,简单的方法是使用 for 循环而不是创建 out 列表。

for u, v in zip(*results):
    print(v + u)

输出

['splitter001', 'stringA', 'stringB']
['splitter_1234', 'stringC']

另一种方法是将子列表转换为字符串,然后用换行符将它们连接在一起以创建一个大字符串。

print('\n'.join([str(v + u) for u, v in zip(*results)]))

这个最终变体将两种类型的组存储到一个迭代器对象中。我想您会同意以前的版本更易于阅读。 :)

it = iter(list(g) for k, g in groupby(data, key=lambda s: s.startswith('splitter')))
out = [u+v for u, v in zip(it, it)]

获取 startswith('splitter') 个元素的索引,然后在这些索引处对列表进行切片

sl = ['splitter001','stringA','stringB','splitter_1234','stringC']

si = [i for i, e in enumerate(sl) if e.startswith('splitter')]
[sl[i:j] for i, j in zip(si, si[1:] + [len(sl)])]

Out[66]: [['splitter001', 'stringA', 'stringB'], ['splitter_1234', 'stringC']]

您可以尝试这样的操作:

首先在 splitter 出现时获取 from to 索引号,然后根据这些索引删除列表:

sl = ['splitter001','stringA','stringB','splitter_1234','stringC']

si = [index for index, value in enumerate(sl) if value.startswith('splitter')]
for i in range(0,len(si),1):

    slice=si[i:i+2]
    if len(slice)==2:
        print(sl[slice[0]:slice[1]])
    else:
        print(sl[slice[0]:])

输出:

['splitter001', 'stringA', 'stringB']
['splitter_1234', 'stringC']