我需要搜索其他東西中的第一個,最後一個,所有或全部事件。爲了避免重複我自己(DRY),我提出了以下解決方案。濫用收益以避免循環中的條件
感興趣的是兩種Searcher
類別的方法search_revisions()
和collect_one_occurence()
。
在SearcherYield
我創建search_revisions()
發電機只能放棄了發電機collect_one_occurence()
收集的第一個結果之後。在SearcherCondition
我把條件放在循環中。這個條件必須在循環的每一次迭代中檢查。
我不能決定我的(ab)使用產量和隨後放棄發電機是否是天才罷工或可怕的黑客攻擊。你怎麼看?你對這種情況有什麼其他想法嗎?
#!/usr/bin/python
class Revision:
# a revision is something like a textfile.
# the search() method will search the textfile
# and return the lines which match the given pattern.
# for demonstration purposes this class is simplified
# to return predefined results
def __init__(self, results):
self.results = results
def search(self, pattern):
return self.results
class AbstractSearcher:
def __init__(self, revisions):
self.revisions = revisions
def search_for_first_occurence(self, pattern):
keys = sorted(self.revisions.iterkeys())
return self.collect_one_occurence(keys, pattern)
def search_for_last_occurence(self, pattern):
keys = sorted(self.revisions.iterkeys(), reverse = True)
return self.collect_one_occurence(keys, pattern)
def search_for_any_occurence(self, pattern):
keys = self.revisions.iterkeys()
return self.collect_one_occurence(keys, pattern)
def search_for_all_occurences(self, pattern):
keys = self.revisions.iterkeys()
return self.collect_all_occurences(keys, pattern)
class SearcherYield(AbstractSearcher):
def search_revisions(self, keys, pattern):
# create generator which yields the results one by one
for key in keys:
rev = self.revisions[key]
result = rev.search(pattern)
if result:
yield result
def collect_one_occurence(self, keys, pattern):
# take the first result and then abandon the generator
for result in self.search_revisions(keys, pattern):
return result
return []
def collect_all_occurences(self, keys, pattern):
# collect all results from generator
results = []
for result in self.search_revisions(keys, pattern):
results.extend(result)
return results
class SearcherCondition(AbstractSearcher):
def search_revisions(self, keys, pattern, just_one):
# collect either all results from all revisions
# or break the loop after first result found
results = []
for key in keys:
rev = self.revisions[key]
result = rev.search(pattern)
if result:
results.extend(result)
if just_one:
break
return results
def collect_one_occurence(self, keys, pattern):
return self.search_revisions(keys, pattern, just_one = True)
def collect_all_occurences(self, keys, pattern):
return self.search_revisions(keys, pattern, just_one = False)
def demo(searcher):
print searcher.__class__.__name__
print 'first:', searcher.search_for_first_occurence('foo')
print 'last: ', searcher.search_for_last_occurence('foo')
print 'any: ', searcher.search_for_any_occurence('foo')
print 'all: ', searcher.search_for_all_occurences('foo')
def main():
revisions = {
1: Revision([]),
2: Revision(['a', 'b']),
3: Revision(['c']),
4: Revision(['d','e', 'f']),
5: Revision([])}
demo(SearcherYield(revisions))
demo(SearcherCondition(revisions))
if __name__ == '__main__':
main()
一些上下文:修訂基本上是文本文件。你可以將它們想象成維基頁面的修訂版本。通常有數百次修訂,有時數千次。每個修訂包含多達數千行文本。也有一些情況,只有少數幾行修訂版本。
在修訂中搜索將在文本中搜索一個模式並返回匹配的行。有時有成千上萬的結果,有時沒有結果。
有時我只需要知道是否有任何修訂結果(搜索任何)。有時我必須收集所有結果以進一步處理(搜索全部)。有時候我只需要第一次修改時使用匹配,有時候只需要最後一次修訂(搜索第一個和最後一個)。
這是waaaaaaay過於複雜。不過,我不能告訴你如何解決它,除非你可以提供更多有用的上下文;我可以從你的例子中得到的是你寫了太多的代碼。你在尋找什麼? – katrielalex 2010-11-15 22:56:09
你需要一個術語移植:你最先/最後調用的是真正的最小/最大鍵,並且(有效地)'排序(可迭代)[0]'而不是'min(可迭代)'有點令人震驚。 – 2010-11-16 00:58:25
@JohnMachin:再次閱讀代碼。該代碼沒有執行'sorted(iterable)[0]'。帶有匹配的第一個修訂不一定是排序列表中的第一個修訂。 – lesmana 2010-11-16 13:14:09