我有一个数据类型,该数据类型由一个列表中的多个元组组成。它代表了亲子关系。
例如[('A', 1), ('A', 2, 1), ('A', 2, 2) ('A', 3), ('B', 1), ('B', 1, 1), ('B', 1, 2), ('C',)]
,其中元组可以具有1、2或3个项目,其格式为(字母,数字,数字)。在上面的示例中,('B', 1)
是('B', 1, 1)
和('B', 1, 2)
的父级,依此类推,直到我们得到一个字母为止。
我的问题是,我该如何创建一个函数来接收类似上面示例的内容,并创建一个嵌套列表,其中将相似的顺序和字母/数字组合在一起。
例如,如何创建类似以下内容的函数:
[('A', 1), ('A', 2, 1), ('A', 2, 2), ('A', 3), ('B', 1), ('B', 1, 1), ('B', 1, 2), ('B', 2), ('B', 3), ('C',)]
并将其转换为:
[[('A', 1), [('A', 2, 1), ('A', 2, 2)] ('A', 3)], [[('B', 1, 1), ('B', 1, 2)], ('B', 2), ('B', 3)], ('C',)]
还请注意,该列表将按照字母和数字顺序进行预排序。输入列表中也只有最低阶元组。 (如果存在父级元组,则它们不会出现在输入列表中)
谢谢!
答案 0 :(得分:0)
我们基本上可以遍历元组,并为每个元组递归地“潜入”数据结构,并添加该元素。但是我认为,至少对于中间结构,列表是不合适的。字典允许快速检索,因此将促进更新。
def to_nested_list(tuples):
data = {}
for tup in tuples:
elem = data
for ti in tup:
elem = elem.setdefault(ti, {})
stck = []
def to_list(source, dest):
for k, v in source.items():
stck.append(k)
if v:
dest.append(to_list(v, []))
else:
dest.append(tuple(stck))
stck.pop()
return dest
return to_list(data, [])
因此,对于给定的样本数据,我们首先构造一个字典,该字典在stck = []
行之前看起来像:
{'A': {1: {}, 2: {1: {}, 2: {}}, 3: {}}, 'B': {1: {1: {}, 2: {}}}, 'C': {}}
接下来,我们通过递归遍历字典来“收获”该结构的元组,并且每次相应的值 not 为空时,添加一个基于“调用路径”构造的元组”添加到相应的子列表。
例如:
>>> to_nested_list([('A', 1), ('A', 2, 1), ('A', 2, 2), ('A', 3), ('B', 1), ('B', 1, 1), ('B', 1, 2), ('C',)])
[[('A', 1), [('A', 2, 1), ('A', 2, 2)], ('A', 3)], [[('B', 1, 1), ('B', 1, 2)]], ('C',)]
这适用于任意长度的元组,只要这些元组的元素都是 hashable (字符串和整数是可哈希的,因此如果元组仅包含字母,则在这里是安全的 s和 number s)。
话虽如此,但我不确定使用嵌套列表是否是个好主意。这样的列表将导致以下事实:验证列表包含某个元组可能要花费大量时间,因为列表的元素不会“提示”该元组的前缀。我认为data
字典可能是更好的表示形式。
答案 1 :(得分:0)
设置
a = [('A', 1), ('A', 2, 1), ('A', 2, 2), ('A', 3), ('B', 1), ('B', 1, 1), ('B', 1, 2), ('B', 2), ('B', 3), ('C',)]
以下解决方案适用于任何深度的树木:
首先,一个辅助函数,如果需要,可以用多余的括号将每个节点包裹起来
def self_wrap(x, n):
output = x
for _ in range(n):
output = [output]
return output
现在,主循环:
out_list = []
for i in range(len(a)):
# add 0th element to out_list
if i == 0:
out_list.append(self_wrap(a[i], len(a[i])-1))
continue
# determine the appropriate bracket level to add a[i]
prev_list = curr_list = out_list
j = 0
while min(len(a[i-1]), len(a[i])) > j and a[i-1][j] == a[i][j]:
prev_list, curr_list = curr_list, curr_list[-1]
print(curr_list, i, j)
j += 1
left_over_len = len(a[i]) - j - 1
# override if last item was parent
if j == len(a[i-1]):
prev_list[-1] = self_wrap(a[i], left_over_len + 1)
continue
# append a[i] to appropriate level and wrap with additional brackets if needed
curr_list.append(self_wrap(a[i], left_over_len) if left_over_len > 0 else a[i])
print(out_list)
此打印
[[('A', 1), [('A', 2, 1), ('A', 2, 2)], ('A', 3)], [[('B', 1, 1), ('B', 1, 2)], ('B', 2), ('B', 3)], ('C',)]
符合预期。
正如人们指出的那样,这种结构不是很有效。有两个原因:
话虽如此,可能是表示路径的唯一方法。