我有一个对象列表:
MyList = [A, B, C, D, E, F, G]
在执行代码期间,这些对象可能会移动位置。这种运动通常是一个接一个地发生,因此(例如)项目“D”可能在“A”之后立即移动。因此,该清单如下:
MyList = [A, D, B, C, E, F, G]
我想知道的是,如果有一种方法(我已经尝试构建算法但我想使代码更短)来跟踪列表上的元素,以便我可以使用当我需要使用它们时,索引将它们恢复到相同的列表中(代码的其他部分无法触及,否则我将在移动循环中实现它)。为了更好地解释,我想知道是否有可能做出这样的事情:
#ORIGINARY LIST
MyList = [A, B, C, D, E, F, G]
Current_Indexes= [0,1,2,3,4,5,6]
#ITERATION THAT MOVES D RIGHT AFTER A
MyList = [A, D, B, C, E, F, G]
Current_Index_Mapping = [0,3,1,2,4,5,6] #method or built-in function???
我想到了一些算法,比如在代码的开头创建一个列表,如下所示:
for i in range(0, len(MyList)):
Current_Index_Mapping.append((i,MyList[i]))
然后提取元组以更新Current_Index_Mapping列表。但是我对Python编程很新,我不知道很多方法和内置函数,所以我想知道:有没有人有更好的想法得到相同的结果?
答案 0 :(得分:5)
将对象的 id 映射到原始indice:
>>> a, b, c, d, e, f, g = [object() for i in range(7)]
>>> lst = [a, b, c, d, e, f, g]
>>> objid_to_idx = {id(obj): idx for idx, obj in enumerate(lst)} # <---
# {
# id(a): 0,
# id(b): 1,
# ...
# id(g): 6,
# }
>>> [objid_to_idx[id(obj)] for obj in lst]
[0, 1, 2, 3, 4, 5, 6]
>>> lst = [a, d, b, c, e, f, g]
>>> [objid_to_idx[id(obj)] for obj in lst]
[0, 3, 1, 2, 4, 5, 6]
>>> lst = [a, d, b, a, c, e, e, f, g]
>>> [objid_to_idx[id(obj)] for obj in lst]
[0, 3, 1, 0, 2, 4, 4, 5, 6]
使用dict comprehension,enumerate
来构建映射。
答案 1 :(得分:0)
也许解决方案是继承list
?
class mylist(list):
def append(self, a):
print('Append %s' % a)
list.append(self, a)
l = mylist()
l.append(42)
print(l)
给出输出:
[~]% python a.py
Append 42
[42]
显然,您可能需要扩展更多方法,例如insert()
,但基本概念应该是明确的。
答案 2 :(得分:0)
你可以试试这个:
def delegate_original_specials(specials):
specialnames = ['__%s__'%s for s in specials.split()]
def wrapit(cls, method):
return lambda self, *args, **kwargs: getattr(self._original, method)(*args, **kwargs)
def dowrap(cls):
for n in specialnames:
setattr(cls, n,
wrapit(cls, n))
return cls
return dowrap
@delegate_original_specials('getitem setitem iter add sub mul div repr str len')
class TrackedObject(object):
__slots__ = ['_original', '_original_id']
__original_names__ = ['_original', '_original_id']
def __init__(self, original, originalid):
self._original = original
self._original_id = originalid
def __getattr__(self, key):
if key in self.__original_names__:
return object.__getattr__(self, key)
else:
return getattr(self._original, key)
def __setattr__(self, key, value):
if key in self.__original_names__:
return object.__setattr__(self, key, value)
else:
return getattr(self._original, key, value)
这里的想法是,不包装列表,而是包装对象,这样您就可以为其分配一个坚持该对象的您选择的ID。
您案例中的示例用法:
l1 = ['A', 'B', 'C', 'D', [1,2,3], 'F']
l2 = [TrackedObject(x, index) for index, x in enumerate(l1)]
# Each item quacks like strings
print l2
['A', 'B', 'C', 'D', 'E', 'F']
len(l2[3])
1
l2[3].lower()
'd'
l2[4][1:]
[2,3]
# But they are tracked
l2[4]._original_id
l3 = l2[4:]
print l3
[[1, 2, 3], 'F']
l3[0]._original_id
4
等。您可能需要添加到委派的特价列表中,但这应该可以帮助您入门。