Python:跟踪列表中移动的元素

时间:2014-01-24 11:21:33

标签: python list python-2.7

我有一个对象列表:

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编程很新,我不知道很多方法和内置函数,所以我想知道:有没有人有更好的想法得到相同的结果?

3 个答案:

答案 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 comprehensionenumerate来构建映射。

答案 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

等。您可能需要添加到委派的特价列表中,但这应该可以帮助您入门。