如何通过特定的字符串元素将字符串列表拆分为字符串的子列表

Posted

技术标签:

【中文标题】如何通过特定的字符串元素将字符串列表拆分为字符串的子列表【英文标题】:How to split a list-of-strings into sublists-of-strings by a specific string element 【发布时间】:2018-05-16 05:04:58 【问题描述】:

我有一个如下的单词列表。我想按. 拆分列表。 Python 3 中有没有更好或有用的代码?

a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
result = []
tmp = []
for elm in a:
    if elm is not '.':
        tmp.append(elm)
    else:
        result.append(tmp)
        tmp = []
print(result)
# result: [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

更新

添加测试用例以正确处理。

a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
b = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.', 'yes']
c = ['.', 'this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.', 'yes']
def split_list(list_data, split_word='.'):
    result = []
    sub_data = []
    for elm in list_data:
        if elm is not split_word:
            sub_data.append(elm)
        else:
            if len(sub_data) != 0:
                result.append(sub_data)
            sub_data = []
    if len(sub_data) != 0:
        result.append(sub_data)
    return result

print(split_list(a)) # [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]
print(split_list(b)) # [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice'], ['yes']]
print(split_list(c)) # [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice'], ['yes']]

【问题讨论】:

它认为有一个单线解决方案,没有额外的库,可以使用列表理解和字符串函数接近您的速度。 @ScottBoston 我认为有一些有用的功能:)。但我很高兴看到许多有趣的答案。 您不应该使用is 运算符来比较字符串顺便说一句。 看来您已经拆分了一次字符串。如果您的 first 拆分是按句子进行的,那么您的问题会简单得多。 【参考方案1】:

您可以使用列表解析和字符串函数joinsplitstrip 的“单行”来完成这一切,并且无需其他库。

a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
b = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.', 'yes']
c = ['.', 'this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.', 'yes']



In [5]: [i.strip().split(' ') for i in ' '.join(a).split('.') if len(i) > 0 ]
Out[5]: [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

In [8]: [i.strip().split(' ') for i in ' '.join(b).split('.') if len(i) > 0 ]
Out[8]: [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice'], ['yes']]

In [9]: In [8]: [i.strip().split(' ') for i in ' '.join(c).split('.') if len(i) > 0 ]
Out[9]: [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice'], ['yes']]

@Craig 有一个更简单的更新:

[s.split() for s in ' '.join(a).split('.') if s]

【讨论】:

稍微简单一点:[s.split() for s in ' '.join(a).split('.') if s] @Craig 谢谢!我讨厌把事情复杂化和想太多。 哦,这很好。但是如果有一个单词包含空格,join 将破坏原始列表。我的意思是像"New York"。我可能会添加这样的测试用例。但这真的很简单也很好。谢谢! @jef 打破“这就是纽约”是一个挑战。进入“这个”、“是”、“纽约”。 如果任何元素有空格或点,则此方法无效。【参考方案2】:

此答案需要安装第 3 方库:iteration_utilities1。包含的split 函数使解决此任务变得简单:

>>> from iteration_utilities import split
>>> a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
>>> list(filter(None, split(a, '.', eq=True)))
[['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

除了使用eq 参数,您还可以定义一个自定义函数来拆分:

>>> list(filter(None, split(a, lambda x: x=='.')))
[['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

如果您想保留'.'s,您也可以使用keep_before 参数:

>>> list(filter(None, split(a, '.', eq=True, keep_before=True)))
[['this', 'is', 'a', 'cat', '.'], ['hello', '.'], ['she', 'is', 'nice', '.']]

请注意,该库只是让它变得更容易 - 无需安装其他库即可轻松完成此任务(请参阅其他答案)。

如果您不希望 '.' 出现在待拆分列表的开头或结尾,则可以删除 filter


1 我是那个库的作者。可通过pipconda-forge 频道与conda 获得。

【讨论】:

【参考方案3】:

我情不自禁,只想从这个好问题中获得乐趣:

import itertools

a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
b = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.', 'yes']
c = ['.', 'this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.', 'yes']

def split_dots(lst):

    dots = [0] + [i+1 for i, e in enumerate(lst) if e == '.']

    result = [list(itertools.takewhile(lambda x : x != '.', lst[dot:])) for dot in dots]

    return list(filter(lambda x : x, result))

print(split_dots(a)) # [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]
print(split_dots(b)) # [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice'], ['yes']]
print(split_dots(c)) # [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice'], ['yes']]

【讨论】:

【参考方案4】:

这是另一种仅使用标准列表操作的方法(不依赖于其他库!)。首先我们找到分割点,然后我们围绕它们创建子列表;请注意,第一个元素被视为特殊情况:

a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
indexes = [-1] + [i for i, x in enumerate(a) if x == '.']

[a[indexes[i]+1:indexes[i+1]] for i in range(len(indexes)-1)]
=> [['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

【讨论】:

【参考方案5】:

您可以使用' '.join 重构字符串并使用正则表达式:

import re
a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
new_s = [b for b in [re.split('\s', i) for i in re.split('\s*\.\s*', ' '.join(a))] if all(b)]

输出:

[['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

【讨论】:

与@ScottBoston 的注释相同:如果任何元素有空格或点,则此方法无效。【参考方案6】:

使用itertools.groupby

from itertools import groupby
a = ['this', 'is', 'a', 'cat', '.', 'hello', '.', 'she', 'is', 'nice', '.']
result = [list(g) for k,g in groupby(a,lambda x:x=='.') if not k]
print (result)
#[['this', 'is', 'a', 'cat'], ['hello'], ['she', 'is', 'nice']]

【讨论】:

以上是关于如何通过特定的字符串元素将字符串列表拆分为字符串的子列表的主要内容,如果未能解决你的问题,请参考以下文章

如何将字符串拆分为列表?

如何将字符串拆分为列表?

文本文件字符串拆分然后将每个元素输出到视图表中

如何将每个 x 个元素拆分一个列表并将这些 x 个元素添加到一个新列表中?

Python:根据索引范围将列表拆分为子列表

如何将逗号分隔的字符串拆分为字符串列表?