Python unflatten list基于第二个列表

时间:2015-09-05 18:52:33

标签: python list python-2.7

我有2个Python列表:

list_a = [[['Ab'], ['Qr', 'Zr']], [['Gt', 'Mh', 'Nt'], ['Dv', 'Cb']]]
list_b = [['Ab', 'QrB', 'Zr'], ['GtB', 'MhB', 'Nt6B', 'DvB', 'Cb6B5']]

我需要根据list_b展开list_a。我需要:

list_c = [['Ab'], ['QrB', 'Zr'], [['GtB', 'MhB', 'Nt6B'], ['DbB', 'Cb6B5']]]

有没有办法获得此list_c

其他信息: 列表将始终定义为:

  • 始终会在list_a中找到list_b的部分字符串。例如。对于一个列表中的Gt,第二个列表中会有GtGtB
  • 每个列表中的条目不能以不同的顺序排列 - 即如果QrZr之前出现在一个列表中,那么它(QrQrB)必须在Zr之前{ {1}}在第二个列表中。
  • 每个列表最多可包含20个字符串。
  • 每个列表只有唯一的字符串..例如。 Gt在任何列表中都不能出现2次或更多次。

尝试:

以下是我的尝试:

list_c = [[],[]]
        for ty,iten in enumerate(list_b):
            for q in iten:
                for l_e in list_a:
                    for items in l_e:
                        for t,qr in enumerate(items):
                            if qr in q:
                                list_c[ty].append([q])

输出是:

[[['Ab'], ['QrB'], ['Zr']], [['GtB'], ['MhB'], ['Nt6B'], ['DbB'], ['Cb6B5']]]

问题在于['QrB'], ['Zr']应该['QrB','Zr']合并list_a,就像它们在for ty,iten in enumerate(list_b): for q in iten: for l_e,m in enumerate(list_a): for ss,items in enumerate(m): for t,qr in enumerate(items): if qr in q: list_a[l_e][ss][t] = q 中合并一样。

尝试2:

[[['Ab'], ['QrB', 'Zr']], [['GtB', 'MhB', 'Nt6B'], ['DvB', 'Cb6B5']]]

这适用于并产生所需的输出:

org.neo4j.kernel.lifecycle.LifecycleException: Component 'org.neo4j.kernel.impl.transaction.XaDataSourceManager@4405a711' was successfully initialized, but failed to start. Please see attached cause exception 

然而,它(尝试2)太长了,我想知道:这似乎不是在Python中这样做的正确方法。是否有更多的Pythonic方法可以做到这一点?

3 个答案:

答案 0 :(得分:2)

如果您关心的是list_a中的子列表的长度,那么可以将list_a转换为其子列表长度,然后使用它来切片list_b的子列表:

# Transform list_a into len of sublists, (generator of generators :)
index_a = ((len(l2) for l2 in l1) for l1 in list_a))  
list_c = []
for flatb, index in zip(list_b, index_a):
    splitb = []
    s = 0
    for i in index:
        splitb.append(flatb[s:s+i])
        s += i
    list_c.append(splitb)

list_c的价值:

[[['Ab'], ['QrB', 'Zr']], [['GtB', 'MhB', 'Nt6B'], ['DvB', 'Cb6B5']]]

答案 1 :(得分:0)

这是任意嵌套深度的递归变量。不太漂亮,但应该有用。

list_a = [[['Ab'], ['Qr', 'Zr']], [['Gt', 'Mh', 'Nt'], ['Dv', 'Cb']]] 
list_b = [['Ab', 'QrB', 'Zr'], ['GtB', 'MhB', 'Nt6B', 'DvB', 'Cb6B5']]

def flatten(l):
    for el in l:
        if isinstance(el, list):
            for sub in flatten(el):
                yield sub
        else:
            yield el

def flitten(l1, l2, i):
    result = []
    for j in l1:
        if isinstance(j, list):
            i, res = flitten(j, l2, i)
            result.append(res)
        else:
            result.append(l2[i])
            i += 1
    return i, result

def flutten(l1, l2):
    i, result = flitten(l1, list(flatten(l2)), 0)
    return result

print(flutten(list_a, list_b))
# prints [[['Ab'], ['QrB', 'Zr']], [['GtB', 'MhB', 'Nt6B'], ['DvB', 'Cb6B5']]]

答案 2 :(得分:0)

考虑到任务的相当复杂的性质,您的代码看起来不会太长(在列表中找到列表中的列表并根据前两个字母将其匹配到另一个列表中的列表,并将原始值替换为匹配的值保留原始列表的嵌套结构...)

你至少可以消除其中一个循环:

for sub_a, sub_b in zip(list_a, list_b):
    for inner_a in sub_a:
        for i, a in enumerate(inner_a):
            for b in sub_b:
                if b.startswith(a):
                    inner_a[i] = b

如果你想要一个更通用的解决方案,它可能会涉及递归,就像@Tibor的回答一样。

编辑:鉴于您提供的额外信息,您可以递归地完成list_a,使用基于扁平版list_b的迭代器替换所有短字符串及其完整版本。这使用了两个列表中字符串以相同顺序出现且没有重复的事实。

def replace_abbreviations(L, full_names):
    for i, item in enumerate(L):
        if isinstance(item, basestring):
            L[i] = full_names.next()
        elif isinstance(item, list):
            replace_abbreviations(item, full_names)

replace_abbreviations(list_a, (item for L in list_b for item in L))

或者你可以得到两个列表中每个字符串的索引的扁平列表,然后循环遍历这些:

def flat_indices(L):
    for i, item in enumerate(L):
        if isinstance(item, list):
            for j, inner_list in flat_indices(item):
                yield (j, inner_list) 
        else:
            yield (i, L)

for (a, i), (b, j) in zip(flat_indices(list_a), flat_indices(list_b)):
    a[i] = b[j]