我有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
,第二个列表中会有Gt
或GtB
。Qr
在Zr
之前出现在一个列表中,那么它(Qr
或QrB
)必须在Zr
之前{ {1}}在第二个列表中。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方法可以做到这一点?
答案 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]