これは「十の位と数字の位を混同している」ということではなく、最初の対戦では十の位が変わらないため、一致する接頭辞の一部と見なされます。
あなたのユースケースでは、このあいまいさに対する非常に簡単な解決策があるようです。隣接するすべてのペアを一致させ、最小値を取るだけです。このような:
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
関数は非常に単純ですが、1 つのことを除いて、map
. 2.7には、 の 2 回目の呼び出しがではなく を返すという厄介なバグがあるため、[2]
代わりにを使用しました。これはそのままのコードには影響しませんが、デバッグを追加すると壊れます。.size
difflib
get_matching_blocks
tuple
namedtuple
print
現在、とをpingすることpairs
によって作成された、すべての隣接する名前のペアのリストです。(これが明確でない場合は、 .Python 3.x を使用している場合は、印刷可能なリストではなく遅延イテレータを返すため、代わりに使用する必要があります。)zip
names
names[1:]
print(zip(names, names[1:])
print(list(zip(names, names[1:]))
zip
次に、それぞれのペアを呼び出しprefix
て、返された最小値を取得します。それmin
がそのためです。(ジェネレーター式を渡していますが、これは最初はトリッキーな概念になる可能性がありますが、リストを構築しないリスト内包表記と考えれば、非常に簡単です。)
読みやすいままにしながら、明らかにこれを 2 ~ 3 行に圧縮できます。
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) であり、M は結果の長さである O(NM) である必要があるだけです。 . さらに、たとえば、最長の接頭辞よりも長い接尾辞が存在することは考えられないわけではないため、間違った結果が返されます。
では、なぜそれを手動でやらないのですか?
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.j 'F'`'FilePrefix10.jpg'
を与えるだけです。したがって、それらをループして、それぞれが他のすべての名前のプレフィックスでもあるかどうかを確認し、最初のものを返します。'FilePrefix10.jp',
, etc. down to
そして、接頭辞ごとではなく文字ごとに考えると、これをさらに速く行うことができます。
def maxprefix(names):
for i, letters in enumerate(zip(*names)):
if len(set(letters)) > 1:
return names[0][:i]
ここでは、最初の文字がすべての名前で同じかどうか、次に 2 番目の文字がすべての名前で同じかどうか、というようにチェックしているだけです。それが失敗するものを見つけたら、プレフィックスはそれまでのすべての文字です (任意の名前から)。
はzip
、名前のリストをタプルのリストに再編成します。最初のリストは各名前の最初の文字、2 番目は各名前の 2 番目の文字、というようになります。つまり、[('F', 'F', 'F', 'F'), ('i', 'i', 'i', 'i'), …]
.
はenumerate
、値とともにインデックスを提供するだけです。したがって、取得する代わりに取得し('F', 'F', 'F', 'F')
ます0, ('F, 'F', F', 'F')
。最後のステップでそのインデックスが必要です。
さて、('F', 'F', 'F', 'F')
それらがすべて同じであることを確認するために、それらをset
. それらがすべて同じである場合、セットには <code>{'F'}, then{'i'}
などの 1 つの要素しかありません。そうでない場合は、複数の要素があります: <code>{'1', '2'}—これが、接頭辞を過ぎたことを知る方法です。