如何按连续性对对象列表进行分组?

时间:2016-04-13 14:34:36

标签: python

给定一个非常大的(千兆字节)任意对象列表(我已经看到了针对整数的类似解决方案),我可以通过等价将其轻松地分组到子列表中吗?就地或通过消耗原始列表的生成器。

l0 = [A,B, A,B,B, A,B,B,B,B, A, A, A,B] #spaces for clarity

期望的结果:

[['A', 'B'], ['A', 'B', 'B'], ['A', 'B', 'B', 'B', 'B'], ['A'], ['A'], ['A', 'B']]

我写了一个像这样的循环版本:

#find boundaries
b0 = []
prev = A
group = A
for idx, elem in enumerate(l0):
    if elem == group:
        b0.append(idx)
    prev = elem
b0.append(len(l0)-1)

for idx, b in enumerate(b0):
    try:
        c = b0[idx+1]
    except:
        break
    if c == len(l0)-1:
        l1.append(l0[b:])
    else:
        l1.append(l0[b:c])

这可以作为生成器gen0(l)来完成,它将起作用:

for g in gen(l0):
    print g
....
['A', 'B']
['A', 'B', 'B']
['A', 'B', 'B', 'B', 'B']
.... 

等?

编辑:使用python 2.6或2.7

编辑:首选解决方案,主要基于接受的答案:

def gen_group(f, items):
    out = [items[0]]
    while items:
        for elem in items[1:]:
            if f(elem, out[0]):
                break
            else:
                out.append(elem)

        for _i in out:
            items.pop(0)
        yield out
        if items:
            out = [items[0]]

g = gen_group(lambda x, y: x == y, l0)

for out in g:
    print out

4 个答案:

答案 0 :(得分:2)

也许是这样的:

def subListGenerator(f,items):
    i = 0
    n = len(items)
    while i < n:
        sublist = [items[i]]
        i += 1
        while i < n and not f(items[i]):
            sublist.append(items[i])
            i += 1
        yield sublist

用过:

>>> items = ['A', 'B', 'A', 'B', 'B', 'A', 'B', 'B', 'B', 'B', 'A', 'A', 'A', 'B']
>>> g = subListGenerator(lambda x: x == 'A',items)
>>> for x in g: print(x)

['A', 'B']
['A', 'B', 'B']
['A', 'B', 'B', 'B', 'B']
['A']
['A']
['A', 'B']

答案 1 :(得分:2)

我认为A是你的断点。

>>> A, B = 'A', 'B'
>>> x = [A,B, A,B,B, A,B,B,B,B, A, A, A,B]
>>> map(lambda arr: [i for i in arr[0]], map(lambda e: ['A'+e], ''.join(x).split('A')[1:]))
[['A', 'B'], ['A', 'B', 'B'], ['A', 'B', 'B', 'B', 'B'], ['A'], ['A'], ['A', 'B']]

答案 2 :(得分:1)

以下是本案例的作品。您可以将l[0] != 'A'条件更改为任何内容。我可能会将其作为参数传递,以便您可以在其他地方重复使用它。

def gen(l_arg, boundary):
    l = l_arg.copy()    # Optional if you want to save memory
    while l:
        sub_list = [l.pop(0)]
        while l and l[0] != boundary:   # Here boundary = 'A'
            sub_list.append(l.pop(0))
        yield sub_list

它假定您的列表开头有'A'。它复制列表,当列表在Gb范围内时,列表不是很好。如果您不关心保留原始列表,可以删除副本以节省内存。

答案 3 :(得分:1)

这是一个执行任务的简单生成器:

def gen_group(L):
    DELIMETER = "A"
    out = [DELIMETER]
    while L:
        for ind, elem in enumerate(L[1:]):
            if elem == DELIMETER :
                break
            else:
                out.append(elem)

        for i in range(ind + 1):
            L.pop(0)

        yield out
        out = [DELIMETER ]

这个想法是减少列表并产生子列表,直到没有任何东西为止。这假设列表以“A”(DELIMETER变量)开头。

示例输出:

for out in gen_group(l0):
    print out

制作

['A', 'B']
['A', 'B', 'B']
['A', 'B', 'B', 'B', 'B']
['A']
['A']
['A', 'B']
['A']

比较时间:

timeit.timeit(s, number=100000)用于测试每个当前答案,其中s是代码的多行字符串(如下所示):

                       Trial 1  Trial 2  Trial 3  Trial 4 |  Avg
This answer (s1):      0.08247  0.07968  0.08635  0.07133   0.07995
Dilara Ismailova (s2): 0.77282  0.72337  0.73829  0.70574   0.73506
John Coleman (s3):     0.08119  0.09625  0.08405  0.08419   0.08642

这个答案是最快的,但它非常接近。我怀疑差异是约翰科尔曼答案中的附加论证和匿名函数。

s1="""l0 = ["A","B", "A","B","B", "A","B","B","B","B", "A", "A", "A","B"]

def gen_group(L):
    out = ["A"]
    while L:
        for ind, elem in enumerate(L[1:]):
            if elem == "A":
                break
            else:
                out.append(elem)

        for i in range(ind + 1):
            L.pop(0)

        yield out
        out = ["A"]

out =gen_group(l0)"""

s2 = """A, B = 'A', 'B'
x = [A,B, A,B,B, A,B,B,B,B, A, A, A,B]
map(lambda arr: [i for i in arr[0]], map(lambda e: ['A'+e], ''.join(x).split('A')[1:]))"""

s3 = """def subListGenerator(f,items):
    i = 0
    n = len(items)
    while i < n:
        sublist = [items[i]]
        i += 1
        while i < n and not f(items[i]):
            sublist.append(items[i])
            i += 1
        yield sublist

items = ['A', 'B', 'A', 'B', 'B', 'A', 'B', 'B', 'B', 'B', 'A', 'A', 'A', 'B']
g = subListGenerator(lambda x: x == 'A',items)"""