在Python中对列表进行“聚类”

3

我一直在尝试对列表进行“聚合”

我的意思是根据中间的项将项目组合在一起,因此当围绕任何一个'-'时,['d','-','g','p','q','-','a','v','i']变成['d-g','p','q-a','v','i']

以下是我的尝试:

def clump(List):
    box = []
    for item in List:
        try:
            if List[List.index(item) + 1] == "-":
                box.append("".join(List[List.index(item):List.index(item)+3]))
            else:
                box.append(item)

        except:
            pass

    return box

然而,它输出的结果(针对上面的示例)为:
['d-g', '-', 'g', 'p', 'q-a', '-', 'a', 'v']

由于我不知道如何跳过接下来的两个项目,因此代码非常混乱,主要是由于try和except语句(如果不使用它,当它到达最后一个项目时,会出现IndexError)。

如何修复它(或完全重写)?

谢谢


下面的答案不错,但我想说的是,一般情况下,如果你要访问数组中不在当前索引位置的元素,使用那种类型的for循环并不是一个好的做法,你可能会想使用一个范围for循环。总体而言。 - John Lexus
@JohnLexus 他目前访问列表的方式只会访问任何给定元素的第一个出现的索引。 - user3483203
@user3483203 好的,我会引用第一个if语句。无论如何,你在技术上是正确的,但我的意思是如果你需要访问另一个元素来获得正确的解决方案,那么他应该使用范围for循环。一般来说这是最好的做法。 - John Lexus
3个回答

5
这里有一个 O(n) 的解决方案,它维护一个标志来确定当前是否正在聚集。根据这个条件,它会操作列表中的最后一项:
def clump(arr):
     started = False
     out = []
     for item in arr:
         if item == '-':
             started = True
             out[-1] += item
         elif started:
             out[-1] += item
             started = False
         else:
              out.append(item)
     return out

实战应用:

In [53]: clump(x)
Out[53]: ['d-g', 'p', 'q-a', 'v', 'i']

如果列表中的第一个项目是短划线,则此解决方案将失败,但这似乎应该是无效的输入。


1
你说得对 - 它永远不会在“-”中启动。谢谢! - Oliver.G

4
这里有一个使用re.sub的解决方案。
>>> import re
>>> l = ['d','-','g','p','q','-','a','v','i']
>>> re.sub(':-:', '-', ':'.join(l)).split(':')
['d-g', 'p', 'q-a', 'v', 'i']

0

这里是另一种使用 itertools.zip_longest 的解决方案。

>>> from itertools import zip_longest
>>> l = ['d','-','g','p','q','-','a','v','i']
>>> [x+y+z if y=='-' else x for x,y,z in zip_longest(l, l[1:], l[2:], fillvalue='') if '-' not in [x,z]]
['d-g', 'g', 'q-a', 'a', 'v', 'i']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接