Python: 如何根据条件获取列表列表的下一个序列?

Python: how to get the next sequence of a list of lists based on a condition?

我使用了一个 NLP 分块器,它错误地将术语 'C++' 和 'C#' 拆分为:C (NN), +(SYM), +(SYM), C (NN), #( SYM).

不正确分块的结果列表如下所示:

l = [['C', 'NN'], ['+', 'SYM'], ['+', 'SYM'], ['C', 'NN'], ['#', 'NN']]

我想 post 处理这个列表,方法是识别每个列表的索引 0 中的字符串 'C' 和下一行 '+'、'+' 或 ' #'。然后我想连接这些字符串,这样 'C','+','+' 只需将它们加在一起就变成 'C++' 。这必须是通用的,因此它应该适用于包含多个不同单词的列表,但仍然连接所需的字符串。

期望的结果:

l_desired = [['C++', 'NN'], ['C#', 'NN']]

我可以独立识别列表中的项目(索引 0),但我不知道如何识别所需的顺序。我的想法是使用 next() 函数,虽然我不知道从哪里开始。

基本上,我只是一个一个地附加每个字母。

当与我们要查找的两个字符串(“C++”或“C#”)匹配时,它会将该值添加到列表中并重置字符串。

    l = [['C', 'NN'], ['+', 'SYM'], ['+', 'SYM'], ['C', 'NN'], ['#', 'NN']]
    
    l_desired = []
    x, y = "", ""
    
    for item in l:
        if x == "":
            y = item[1]
            
        x += item[0]
        
        if x in ["C++", "C#"]:
            l_desired.append([x, y])
            x, y = "", ""       

print("RESULT: " + l_desired)
# RESULT: [['C++', 'NN'], ['C#', 'NN']]

您可以遍历列表并检查第一个元素是否为字母,在这种情况下作为新项追加,否则更新最后一项:

from string import ascii_letters

letters = set(ascii_letters)

out = []
for e in l:
    if e[0][0] in letters:
        out.append(e.copy()) # making a copy not to affect original list
    elif out: # this is to check that out is not empty (edge case)
        out[-1][0] += e[0]

或者使用符号黑名单:

symbols = set('+#')

out = []
for e in l:
    if e[0] in symbols and out:
        out[-1][0] += e[0]
    else:
        out.append(e.copy())

输出:

[['C++', 'NN'], ['C#', 'NN']]

这是生成器的简单实现,它将读取原始列表作为迭代器并“标记化”它(再次 - 简单地):

def the_generator(l):
    it = iter(l)

    def get_tok():
        x = it.next()
        return (",".join(x),x)

    while True:
        tok1 = get_tok()
        tok3 = None
        if tok1[0] != 'C,NN':
            yield tok1[1]
            continue
        tok2 = get_tok()
        if tok2[0] == '#,NN':
            yield ['C#','NN']
            continue
        if tok2[0] == '+,SYM':
            tok3 = get_tok()
            if tok3[0] == '+,SYM':
                yield ['C++','NN']
                continue
        yield tok1[1]
        yield tok2[1]
        if tok3:
            yield tok3[1]


l = [['Dog', 'NN'], ['C', 'NN'], ['+', 'SYM'], ['+', 'SYM'], ['C', 'NN'], ['#', 'NN'], ['C', 'NN'], ['+','SYM'], ['#', 'NN']]

for x in the_generator(l):
  print(x)

输出:

['Dog', 'NN']
['C++', 'NN']
['C#', 'NN']
['C', 'NN']
['+', 'SYM']
['#', 'NN']

生成器不会一次转换所有列表,仅在需要时转换。要一次创建一个新列表,您可以执行 list(the_generator(l)).

我正在用 join() 对各个标记进行字符串化以简化比较。当原始迭代结束并且 .next() 引发 StopIteration.

时,while True 循环自然结束