我有以下代码:
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的长度增加,因此该方法的性能会明显下降,因为这确实存在;那只是纯粹的数学!从用户角度来看,它从有效的瞬时变为花费大量的时间(尽管少于一秒钟,至少在我的机器上).
仅当我可以将OldLinkData中元组的第一个元素与ChangedLinks中元组的第一个元素相同的对象匹配时,才需要向ReplaceQueue列表中添加新元素. (这些元组元素在它们各自的列表中是唯一的,例如,OldLinkData [0] [0]在OldLinkData的所有其他成员中是唯一的,对于OldLinkData [1] [0]也是相同的,依此类推.)我可以想到的是,要像上面的代码那样遍历每个集合/列表并比较元组元素.
有没有更有效的方法可以做到这一点?理想情况下,我希望有一种方法可以快速构造仅OldLinkData成员的列表,这些成员与ChangedLinks的成员之一共享第一个元素,其顺序与ChangedLinks相同,以便我可以对列表进行并排比较-侧.但是我不知道如何开始解决这个问题.
编辑:预期输入和输出的一些示例:
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])')]
明确地说,这是从控制台以工作代码打印的实际输入和输出.我正在寻找一种比当前代码更有效地实现相同结果的方法.
OldLinkData和NewLinkData中的元组具有以下形式:
(Page.Page object at X, String)
该代码的目的是产生ReplaceQueue,这是旧值和新值的列表,用于替换一系列字符串中的子字符串(分层笔记本中的页面内容). ReplaceQueue的内容必须缩小到内存中相同的Page.Page对象在OldLinkData和NewLinkData上具有两个不同的关联“链接”(用某些markdown语法包装的整数索引路径的字符串表示)的情况.
OldLinkData和NewLinkData之间的区别是通过ChangedLinks作为set(NewLinkData)-set(OldLinkData)获得的,但是随后我需要在ReplaceQueue中将更改的字符串彼此关联.
LinkUpdateTokenID整数只是一个中间步骤,因此我可以保证str.replace的唯一参数,并且当两个对象交换链接字符串时,不会造成混乱.
编辑:感谢@ParitoshSingh,以下代码明显更快:
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的此特定方案.
对于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(平均±标准偏差,共运行7次,每个循环100000次)
NewCode:每个循环1.62 µs±98.4 ns(平均±标准偏差,共运行7次,每个循环1000000次)