基本原理:我启动一个包含多个堆的列表的脚本。在每一步,我都想加入"堆,但保持两个连接的索引指向同一个元素。
简而言之,给定一个可变元素列表,list[a] is list[b]
返回True
,如何在保留list[a] = [new]
和list[a]
的同时分配(list[b]
)引用同一个可变容器?
因此,例如,如果每个堆都由一个字母表示,我们就有
t is ['a', 'b', 'c', 'd']
t is ['ac', 'b', 'ac', 'd'] (0 and 2 merge)
t is ['abc', 'abc', 'abc', 'd'] (0 and 1 merge, but since 0 also refers to 2, it is as if 0/2 and 1 merged... into 0/1/2)
在这个阶段,如果我做了set(map(id, t))
,我希望它只有两个元素。
我的问题是我似乎无法直接影响被指向的对象,因此我必须迭代整个列表,挑选出与合并索引匹配的任何ID,并直接分配。
有没有办法改变底层对象而不是指向它的所有指针?
所需行为的完整示例:
>>> my_list = [['a'], ['b'], ['c']]
>>> merge(my_list, 0, 2) # mutates, returns None
>>> my_list
[['a', 'c'], ['b'], ['a', 'c']]
>>> my_list[0] is my_list[2]
True
>>> merge(my_list, 0, 1)
>>> my_list
[['a', 'c', 'b'], ['a', 'c', 'b'], ['a', 'c', 'b']]
>>> my_list[0] is my_list[1]
True
>>> my_list[1] is my_list[2]
True
问题是,如果在merge
范围内,我只需致电
my_list[arg1] = my_list[arg2] = my_list[arg1]+my_list[arg2]
它仅影响arg1
和arg2
的条目。我希望它影响可能指向my_list[arg1]
或my_list[arg2]
元素的任何其他条目,以便最终my_list
只是指向同一个大堆的指针的集合,吸收了所有小孩子。
答案 0 :(得分:1)
这就像你要得到的那样接近:
def merge(primary, first, second):
primary[first] += primary[second]
primary[second] = primary[first]
first = ['a']
second = ['b']
third = ['c']
main = [first, second, third]
print(main)
merge(main, 0, 2)
print(main)
assert main[0] is main[2]
merge(main, 0, 1)
print(main)
assert main[1] is main[2]
print(first, second, third)
和打印输出:
[['a'], ['b'], ['c']]
[['a', 'c'], ['b'], ['a', 'c']]
[['a', 'c', 'b'], ['a', 'c', 'b'], ['a', 'c', 'b']]
(['a', 'c', 'b'], ['b'], ['c'])
如您所见,列表元素最终都是同一个对象,但进入主列表的列表不是。
修改强>
不幸的是,如果您不在每个合并中包含第一个列表元素,这也会失败。
所以这里没有捷径。如果您希望每个元素都是相同的元素,或者只是相等,那么您将不得不遍历列表以完成它:
def merge(primary, first, second):
targets = primary[first], primary[second]
result = primary[first] + primary[second]
for index, item in enumerate(primary):
if item in targets:
primary[index] = result
答案 1 :(得分:1)
链分配:
>>> my_list = [['a'], ['b'], ['c']]
>>> my_list[0] = my_list[2] = my_list[0]+my_list[2]
>>> my_list
[['a', 'c'], ['b'], ['a', 'c']]
>>> my_list[0] += [1,2,3]
>>> my_list
[['a', 'c', 1, 2, 3], ['b'], ['a', 'c', 1, 2, 3]]
>>>
如果您先a=c=a+c
,则会产生a==c==_list_object_001
;当你执行a=b=a+b
第二次时,会产生a==b==_list_object_002
,所以它出错了
如果您不处理作业顺序,即使使用pointer
,也无法执行此操作。我认为你应该保留一张地图以使事情正确。
答案 2 :(得分:1)
据我所知,我不认为使用python列表的可变性可以做到这一点。如果你有元素X和Y,这两个元素已经是其他元素的合并,并且你想合并它们,列表可变性将无法将更改发送给双方。您可以使X,Y和指向与X相同的对象的所有元素相同,或者您可以使X,Y和指向与Y相同的对象的所有元素相同,但不能同时使用。
我认为最好的办法是定义一个自定义对象来表示元素,这些元素具有父节点和最终父节点的概念。
class Nodes(object):
def __init__(self, input1):
self.parent = None
self.val = [input1]
def ultimate_parent(self):
if self.parent:
return self.parent.ultimate_parent()
else:
return self
def merge(self, child):
self.ultimate_parent().val += child.ultimate_parent().val
child.ultimate_parent().parent = self.ultimate_parent()
def __repr__(self):
return str(self.ultimate_parent().val)
def merge(node_list, i, j):
node_list[i].merge(node_list[j])
list1 = [Nodes(x) for x in 'abcd']
print list1
merge(list1, 0, 2)
print list1
merge(list1, 1, 3)
print list1
merge(list1, 0, 1)
print list1
这将输出:
[['a', 'c'],['b'],['a', 'c'],['d']]
[['a', 'c'],['b', 'd'],['a', 'c'],['b', 'd']]
[['a', 'c', 'b', 'd'],['a', 'c', 'b', 'd'],['a', 'c', 'b', 'd'],['a', 'c', 'b', 'd']]