我有以下代码:
ChangedLinks = set(NewLinkData) - set(OldLinkData)
ReplaceQueue = []
LinkUpdateTokenID = 0
for ChangedLink in ChangedLinks:
for OldLink in OldLinkData:
if ChangedLink[0] is OldLink[0]:
ReplaceStrings = (OldLink[1], "<<LINK UPDATE TOKEN " + str(LinkUpdateTokenID) + ">>", ChangedLink[1])
ReplaceQueue.append(ReplaceStrings)
LinkUpdateTokenID += 1
ChangedLinks
是一组元组,OldLinkData
是元组的列表。当
ChangedLinks
和OldLinkData
的长度增加时,这种方法的性能明显下降,因为当然有;这只是纯粹的数学问题从用户的角度来看,它实际上是瞬间的,需要花费相当多的时间(虽然不到一秒钟,至少在我的机器上是这样)。只有当我可以将
ReplaceQueue
中元组的第一个元素与OldLinkData
中元组的第一个元素作为同一对象匹配时,我才需要向ChangedLinks
列表中添加一个新元素(这些元组元素在各自的列表中是唯一的,如中所示,OldLinkData[0][0]
在OldLinkData
的所有其他成员中是唯一的,OldLinkData[1][0]
在OldLinkData
的所有其他成员中也是唯一的,ChangedLinks
的所有其他成员中都是唯一的,ChangedLinks
的所有其他成员都是唯一的,OldLinkData
的所有其他成员都是唯一的,NewLinkData
的所有其他成员都是唯一的,ReplaceQueue
的所有其他成员都是唯一的。)有没有更有效的方法来做到这一点?理想情况下,我想用某种方法快速构造一个列表,其中只有
ReplaceQueue
的成员与Page.Page
的一个成员共享其第一个元素,顺序与OldLinkData
相同,这样我就可以并排比较这些列表但我不知道如何开始解决这个问题。编辑:预期输入和输出的一些示例:
OldLinkData: [(<Page.Page object at 0x035AF070>, ']([0])'), (<Page.Page object at 0x043FE4F0>, ']([0, 0])'), (<Page.Page object at 0x043FE590>, ']([0, 0, 0])'), (<Page.Page object at 0x043FE5B0>, ']([0, 1])')]
NewLinkData: [(<Page.Page object at 0x035AF070>, ']([0])'), (<Page.Page object at 0x043FE5B0>, ']([0, 0])'), (<Page.Page object at 0x043FE4F0>, ']([0, 1])'), (<Page.Page object at 0x043FE590>, ']([0, 1, 0])')]
ChangedLinks: {(<Page.Page object at 0x043FE590>, ']([0, 1, 0])'), (<Page.Page object at 0x043FE5B0>, ']([0, 0])'), (<Page.Page object at 0x043FE4F0>, ']([0, 1])')}
ReplaceQueue: [(']([0, 0, 0])', '<<LINK UPDATE TOKEN 0>>', ']([0, 1, 0])'), (']([0, 1])', '<<LINK UPDATE TOKEN 1>>', ']([0, 0])'), (']([0, 0])', '<<LINK UPDATE TOKEN 2>>', ']([0, 1])')]
为了清楚起见,这是工作代码中从控制台打印的实际输入和输出。我正在寻找一种比当前代码更有效地实现相同结果的方法。
NewLinkData
和OldLinkData
中的元组的形式为:(Page.Page object at X, String)
代码的目的是生成
NewLinkData
,这是一个新旧值列表,用于替换一系列字符串(层次笔记本中的页面内容)中的子字符串。ChangedLinks
的内容必须缩小到这样的情况:内存中的同一对象在set(NewLinkData) - set(OldLinkData)
和ReplaceQueue
之间有两个不同的关联“链接”(以某种标记语法包装的整数索引路径的字符串表示)。LinkUpdateTokenID
和str.replace
之间的差异是通过as获得的,但是我需要在中将更改的字符串相互关联。整数只是一个中间步骤,这样我就可以保证的参数是唯一的,并且在两个对象交换链接字符串时不会弄糟。
编辑:感谢@paritoshingh,下面的代码明显更快:
def GetLinkData(self):
LinkData = {}
LinkData[id(self.RootPage)] = "](" + self.JSONSerializer.SerializeDataToJSONString(self.RootPage.GetFullIndexPath(), Indent=None) + ")"
self.AddSubPageLinkData(self.RootPage, LinkData)
return LinkData
def AddSubPageLinkData(self, CurrentPage, LinkData):
for SubPage in CurrentPage.SubPages:
LinkData[id(SubPage)] = "](" + self.JSONSerializer.SerializeDataToJSONString(SubPage.GetFullIndexPath(), Indent=None) + ")"
self.AddSubPageLinkData(SubPage, LinkData)
def UpdateLinks(self, OldLinkData, NewLinkData):
ReplaceQueue = []
for PageID in NewLinkData:
if PageID in OldLinkData:
if NewLinkData[PageID] != OldLinkData[PageID]:
ReplaceStrings = (OldLinkData[PageID], "<<LINK UPDATE TOKEN" + str(PageID) + ">>", NewLinkData[PageID])
ReplaceQueue.append(ReplaceStrings)
for ReplaceStrings in ReplaceQueue:
self.SearchWidgetInst.ReplaceAllInNotebook(SearchText=ReplaceStrings[0], ReplaceText=ReplaceStrings[1], MatchCase=True, DelayTextUpdate=True)
for ReplaceStrings in ReplaceQueue:
self.SearchWidgetInst.ReplaceAllInNotebook(SearchText=ReplaceStrings[1], ReplaceText=ReplaceStrings[2], MatchCase=True, DelayTextUpdate=True)
最佳答案
编辑:对于遇到类似问题的用户,请参考下面更通用的解决方案。此编辑仅处理操作的此特定场景。
对于OP,可以使用哈希值加快查找速度对于这个特定的用例,请尝试id() function
警告:注意事项。ID函数保证为同时共存的对象生成唯一值,但仅保证在CPython中链接到内存地址,其他实现可能不同。
OldLinkData = list(zip("123","abc"))
print(OldLinkData)
#[('1', 'a'), ('2', 'b'), ('3', 'c')]
NewLinkData = list(zip('1245','axyz'))
print(NewLinkData)
#[('1', 'a'), ('2', 'x'), ('4', 'y'), ('5', 'z')]
#code:
#Create a key value mapping based on the id of objects.
OldLinkDataDict = {id(OldLink[0]): OldLink for OldLink in OldLinkData}
#{244392672200: ('1', 'a'), 244392672368: ('2', 'b'), 244420136496: ('3', 'c')}
ReplaceQueue = []
LinkUpdateTokenID = 0
for NewLink in NewLinkData:
new_id = id(NewLink[0])
if new_id in OldLinkDataDict: #only consider cases where NewLink exists in OldLinkData
if NewLink[1] != OldLinkDataDict[new_id][1]: #only when the value changes (similar to ChangedLinks)
ReplaceStrings = (OldLinkDataDict[new_id][1],
"<<LINK UPDATE TOKEN " + str(LinkUpdateTokenID) + ">>",
NewLink[1])
ReplaceQueue.append(ReplaceStrings)
LinkUpdateTokenID += 1
print(ReplaceQueue)
#[('b', '<<LINK UPDATE TOKEN 0>>', 'x')]
如果您感到好奇,这个演示只会起作用,因为python会将int对象缓存为小数字。[-5 to 256]
广义解
如果比较对象是散列的,那么通过将oldlinkdata的数据类型更改为字典,可以看到非常好的效果。Link to Docs。因为字典键是散列的,所以字典查找是一个常量时间操作
O(1)
,不需要在字典中迭代。#Dummy data
OldLinkData = list(zip("123","abc"))
print(OldLinkData)
#[('1', 'a'), ('2', 'b'), ('3', 'c')]
NewLinkData = list(zip('1245','axyz'))
print(NewLinkData)
#[('1', 'a'), ('2', 'x'), ('4', 'y'), ('5', 'z')]
#code:
#ChangedLinks = set(NewLinkData) - set(OldLinkData) #Remove this, set creation requires an iteration anyways
OldLinkDataDict = dict(OldLinkData)
print(OldLinkDataDict)
#{'1': 'a', '2': 'b', '3': 'c'}
ReplaceQueue = []
LinkUpdateTokenID = 0
for NewLink in NewLinkData:
if NewLink[0] in OldLinkDataDict: #only consider cases where NewLink exists in OldLinkData
if NewLink[1] != OldLinkDataDict[NewLink[0]]: #only when the value changes (similar to ChangedLinks)
ReplaceStrings = (OldLinkDataDict[NewLink[0]],
"<<LINK UPDATE TOKEN " + str(LinkUpdateTokenID) + ">>",
NewLink[1])
ReplaceQueue.append(ReplaceStrings)
LinkUpdateTokenID += 1
print(ReplaceQueue)
#[('b', '<<LINK UPDATE TOKEN 0>>', 'x')]
一些比较。请注意,理想情况下,您应该只创建一次字典,但我将其包含在时间比较中,以防您无法永久更改oldlinkdata的数据类型。在这种情况下,您只需要根据需要创建字典进行比较。
OldLinkData = list(zip("123","abc"))
NewLinkData = list(zip('1245','axyz'))
基线
%%timeit
ChangedLinks = set(NewLinkData) - set(OldLinkData)
ReplaceQueue = []
LinkUpdateTokenID = 0
for ChangedLink in ChangedLinks:
for OldLink in OldLinkData:
if ChangedLink[0] is OldLink[0]:
ReplaceStrings = (OldLink[1], "<<LINK UPDATE TOKEN " + str(LinkUpdateTokenID) + ">>", ChangedLink[1])
ReplaceQueue.append(ReplaceStrings)
LinkUpdateTokenID += 1
新代码
%%timeit
OldLinkDataDict = dict(OldLinkData)
ReplaceQueue = []
LinkUpdateTokenID = 0
for NewLink in NewLinkData:
if NewLink[0] in OldLinkDataDict: #only consider cases where NewLink exists in OldLinkData
if NewLink[1] != OldLinkDataDict[NewLink[0]]: #only when the value changes (similar to ChangedLinks)
ReplaceStrings = (OldLinkDataDict[NewLink[0]],
"<<LINK UPDATE TOKEN " + str(LinkUpdateTokenID) + ">>",
NewLink[1])
ReplaceQueue.append(ReplaceStrings)
LinkUpdateTokenID += 1
基线:
2.16 µs ± 52.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
新代码:
1.62 µs ± 98.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)