我正在研究一个问题,要求我定义一个函数copy_tree
,该函数接受参数tree
(可能包含元组的元组)并返回树的副本(即存储在不同的内存位置)。
我当前的代码是:
def copy_tree(tree):
new_tree = ()
for i in tree:
new_i = (i,) + ()
new_tree = new_tree + new_i
return new_tree
但是,这不适用于嵌套的元组,因为内部的元组不是“复制”的,而是被引用的。
例如如果我跑
a = ((3, 2), 1, (4,), 5)
b = copy_tree(a)
print(a[0] is b[0])
输出必须为False
。
如何复制元组?
编辑:不允许使用deepcopy
模块。
答案 0 :(得分:3)
这是一个递归解决方案,它可以深层复制(嵌套)元组,保留其他对象不变,并且不使用copy
模块:
def copy_tree(tree):
if isinstance(tree, tuple):
return tuple(map(copy_tree, tree))
# or, maybe more readable
# return tuple(copy_tree(x) for x in tree)
return tree
如果您事先不知道嵌套级别,那么递归绝对是最优雅的方法。
答案 1 :(得分:1)
仅将现有元组传递给tuple
构造函数将不会创建该构造函数的新副本。相反,您应该将等效列表传递给tuple
构造函数以创建元组的副本:
def copy_tuple(t):
output = []
for i in t:
if isinstance(i, tuple):
output.append(copy_tuple(i))
else:
output.append(i)
return tuple(output)
这样:
a = ((3, 2), 1, (4,), 5)
b = copy_tuple(a)
print(a)
print(b)
print(a[0] is b[0])
将输出:
((3, 2), (4,), 5)
((3, 2), (4,), 5)
False
答案 2 :(得分:1)
您的代码缺少递归步骤-您仅复制顶级元组。
def copy_tree(tree):
new_tree = ()
for i in tree:
# i is not copied
new_i = (i,) + ()
new_tree = new_tree + new_i
return new_tree
添加递归会生成树的每一层的副本。请注意,您可以仅复制 个元组:
def copy_tree(tree):
new_tree = ()
for i in tree:
# recursively copy i *if it is a tuple*
if isinstance(i, tuple):
new_i = (copy_tree(i),)
else:
new_i = (i,)
new_tree = new_tree + new_i
return new_tree
递归可修复结果,但是您采用的方法效率低下-创建并丢弃了许多瞬时元组。每次通过+
“扩展”一个元组时,都会丢弃旧的元组,并创建一个新的元组。
第一步是延迟创建元组,直到所有子级都被转换为止
def copy_tree(tree):
children = []
for child in tree:
# we *always* preserve a child, so ternary if expresses this better
child = copy_tree(child) if isinstance(child, tuple) else child
children.append(child)
# create a new tuple including all children
return tuple(children)
由于该列表仅存在,可以变成一个元组,因此我们也可以摆脱它:生成器表达式允许将转换后的子代直接馈送到tuple
构造函数。
def copy_tree(tree):
# generator expression - only run when consumed by tuple later on
children = (
copy_tree(child) if isinstance(child, tuple) else child
for child in tree
)
return tuple(children)
当然,您也可以将生成器表达式直接放在tuple
内。
答案 3 :(得分:0)
我认为问题的意图是使用某种递归。以下代码将以递归方式深度复制树。
def copy_tree(tree):
new_tree = ()
for node in tree:
if type(node) == tuple:
new_tree += (copy_tree(node),)
else:
new_tree += (node,)
return new_tree
a = ((3, 2), 1, (4,), 5)
b = copy_tree(a)
print(a[0] is b[0])
最后打印会给你False
答案 4 :(得分:0)
这是一个简单的版本,它通过向tuple
构造函数提供递归生成器来复制树。为了测试它,我编写了另一个递归函数compare_trees
,您可以使用它来检查对应的元组不相同(使用is
),以及对应的内部项目具有相同的值(使用==
。
def copy_tree(tree):
return tuple(copy_tree(u) if isinstance(u, tuple) else u for u in tree)
def compare_trees(tree1, tree2, indent=''):
print(indent, 'tree1', tree1, 'tree2', tree2, 'identical', tree1 is tree2)
indent += ' '
for u1, u2 in zip(tree1, tree2):
if isinstance(u1, tuple) and isinstance(u2, tuple):
compare_trees(u1, u2, indent)
else:
print(indent, 'item1', u1, 'item2', u2, 'equal', u1 == u2)
a = ((3, 2), 1, (4,), 5, (6, (7, 8)))
b = copy_tree(a)
print(b)
compare_trees(a, b)
输出
((3, 2), 1, (4,), 5, (6, (7, 8)))
tree1 ((3, 2), 1, (4,), 5, (6, (7, 8))) tree2 ((3, 2), 1, (4,), 5, (6, (7, 8))) identical False
tree1 (3, 2) tree2 (3, 2) identical False
item1 3 item2 3 equal True
item1 2 item2 2 equal True
item1 1 item2 1 equal True
tree1 (4,) tree2 (4,) identical False
item1 4 item2 4 equal True
item1 5 item2 5 equal True
tree1 (6, (7, 8)) tree2 (6, (7, 8)) identical False
item1 6 item2 6 equal True
tree1 (7, 8) tree2 (7, 8) identical False
item1 7 item2 7 equal True
item1 8 item2 8 equal True
我想讽刺的是,测试代码比我们要测试的代码更大,更复杂,但这有时是不可避免的。 ;)
答案 5 :(得分:-1)
您应该使用copy module。
该模块具有两种功能,可以满足您的需求:复制和深度复制。 复制的功能与copy_tree相同。
例如,如果您这样做:
import copy
l = [[0],[0]]
l2 = copy.copy(l)
l[0] = [1]
l[1][0] = [1]
则l2将是[[0],[1]] l2的第一个元素没有更改,因为您替换了l个第一个元素。但是,第二个元素已更改,因为您突变了l的第二个元素,该元素是对l2的引用。
如果您使用Deepcopy:
import copy
l = [[0],[0]]
l2 = copy.deepcopy(l)
l[0] = [1]
l[1][0] = [1]
那么l2将是[[0],[0]],因为l和l2不再共享任何东西。