這並不是說它「混淆了十和數字的位置」,而是因爲在第一場比賽中,十人位置並沒有不同,所以它被認爲是匹配前綴的一部分。
對於您的用例,似乎有一個相當簡單的解決方案來解決這種模糊問題:只匹配所有相鄰的對,並取最小值。就像這樣:
def prefix(x, y):
comp = SequenceMatcher(None, x, y)
matches = comp.get_matching_blocks()
prefix_match = matches[0]
prefix_size = prefix_match[2]
return prefix_size
pairs = zip(files, files[1:])
matches = (prefix(x, y) for x, y in pairs)
prefixlen = min(matches)
prefix = files[0][:prefixlen]
的prefix
功能是非常簡單的,除了一兩件事:我把它取兩個值,而不是兩個參數的一個元組,只是爲了使其更容易與map
調用。我使用[2]
而不是.size
,因爲在2.7 difflib
中有一個令人討厭的錯誤,其中第二次調用get_matching_blocks
可能會返回tuple
而不是namedtuple
。這不會影響代碼,但如果您添加一些調試print
它會中斷。
現在,pairs
是由zip
ping合在一起創建的所有相鄰名稱對的列表names
和names[1:]
。 (如果不明確,print(zip(names, names[1:])
。如果您使用的是Python 3.x,則需要使用print(list(zip(names, names[1:]))
,因爲zip
返回的是惰性迭代器而不是可打印列表。)
現在我們只想請在每個配對上撥打prefix
,然後取回我們返回的最小值。這就是min
的用途。 (我通過它generator expression,這可能是一個棘手的概念 - 但如果你只是想它是一個list comprehension,不建立列表,這很簡單。)
你可以明顯壓縮這個進入二,三線同時還留下可讀性:
prefixlen = min(SequenceMatcher(None, x, y).get_matching_blocks()[0][2]
for x, y in zip(files, files[1:]))
prefix = files[0][:prefixlen]
然而,這是值得考慮的SequenceMatcher
可能是矯枉過正這裏。它尋找最長匹配任何地方,而不僅僅是最長的前綴匹配,這意味着它基本上是字符串長度的O(N^3),當它只需要是O(NM),其中M是長度結果。另外,不可思議的是,可能有一個比最長的前綴長的後綴,所以它會返回錯誤的結果。
那麼,爲什麼不能手動做呢?
def prefixes(name):
while name:
yield name
name = name[:-1]
def maxprefix(names):
first, names = names[0], names[1:]
for prefix in prefixes(first):
if all(name.startswith(prefix) for name in names):
return prefix
prefixes(first)
只是給你'FilePrefix10.jpg'
,'FilePrefix10.jp',
'FilePrefix10.j , etc. down to
' F'`。所以我們只是循環,檢查每一個是否也是所有其他名稱的前綴,並返回第一個。
而且你可以通過前綴由字符,而不是前綴字符思維更快做到這一點:
def maxprefix(names):
for i, letters in enumerate(zip(*names)):
if len(set(letters)) > 1:
return names[0][:i]
在這裏,我們只是檢查的第一個字符是否在所有名稱相同,那麼第二個字符在所有名字中是否相同,等等。一旦我們找到失敗的地方,那麼前綴就是所有的字符(來自任何名字)。
zip
將名稱列表重組爲一個元組列表,其中第一個是每個名稱的第一個字符,第二個是每個名稱的第二個字符,依此類推。那就是[('F', 'F', 'F', 'F'), ('i', 'i', 'i', 'i'), …]
。
enumerate
只是給了我們指數和價值。所以,而不是得到('F', 'F', 'F', 'F')
你得到0, ('F, 'F', F', 'F')
。我們需要該指標進行最後一步。
現在,檢查('F', 'F', 'F', 'F')
都是一樣的,我只是把它們放在set
。如果他們都是一樣的,那麼這個集合將只有一個元素,即{'F'}
,然後是{'i'}
等。如果它們不是,它將具有多個元素{'1', '2'}
-這就是我們知道我們已經超過了前綴。
@ mh00h:你首先想明白哪一個?你知道'map',comprehensions,generator和'all'是如何工作的嗎? – abarnert
我現在正在消化它。你讓我去記錄很多東西(我寧願這樣做比在這裏發佈);在我消化所有這一切的同時忍受着我!真棒回答。這裏學到很多東西。 – mh00h
@ mh00h:好的,很酷。我會嘗試在答案中加入一些解釋 - 一些未來的搜索者一起尋找相同的問題可能不會像你一樣勤奮。如果您發現任何不清楚的東西,請告訴我們,以便我們改進。 (另外,如果它們中的任何一個沒有實際工作,請告訴我;在最初編寫和測試它們之後,我編輯了它們幾次...) – abarnert