"열 번째와 자릿수가 혼동 스럽다"는 것은 아닙니다. 첫 번째 매치업에서 열 번째 장소는 다르지 않으므로 일치하는 접두어의 일부로 간주됩니다.
사용 사례에 따라이 모호성에 대한 아주 쉬운 해결책이있는 것처럼 보입니다. 인접한 모든 쌍을 일치시키고 최소한을 취하십시오. 이처럼 :
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
로 전화를 할 수 있도록, 대신 두 개의 인수의 두 값의 단일 튜플을했다. 그리고 두 번째 호출 get_matching_blocks
에 namedtuple
대신 tuple
을 반환 할 수있는 2.7 difflib
에 성가신 버그가있어서 .size
대신 [2]
을 사용했습니다. 이것은 코드에 그대로 영향을 미치지 않지만 디버그를 추가하면 print
가 중단됩니다.
이제 pairs
은 zip
ping과 함께 및 names[1:]
으로 생성 된 모든 인접 쌍 이름 목록입니다. (이, 명확하지 않으면 파이썬 3.x를을 사용하는 경우 zip
가 인쇄 목록 대신 게으른 반복자를 반환하기 때문에 print(zip(names, names[1:])
., 당신은 대신 print(list(zip(names, names[1:]))
해야합니다.)
이제 우리가 원하는 각 쌍에 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) 일 필요가 있음을 의미하는 어디서나을 찾습니다. 결과. 게다가 가장 긴 접두사보다 긴 접미사가있을 수 있다는 것은 상상도 할 수 없으므로 잘못된 결과를 반환합니다.
그래서 수동으로하지 않는 이유는 무엇입니까?
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 : 어느 것을 먼저 이해하려고합니까? '지도', 이해력, 생성자,'모두'가 어떻게 작동하는지 알고 있습니까? – abarnert
나는 지금 그것을 모두 소화하고있다. 당신은 저에게 문서를 많이 보냈습니다. (나는 여기에 게시하는 것보다 먼저 그렇게 할 것입니다.) 내가 그것 모두를 소화하는 동안 나와 맺어 라!! 굉장한 대답. 여기에서 배울 점이 많습니다. – mh00h
@ mh00h : 좋습니다. 저는 답에 몇 가지 설명을 추가하려고합니다. 같은 문제를 찾고있는 미래의 검색자가 당신만큼 열심히하지 않을 수도 있습니다. 명확하지 않은 것을 발견하면 개선 할 수 있도록 알려주십시오. (또한 실제로 작동하지 않는 사람이 있으면 알려주세요; 처음에 글을 쓰고 테스트 한 후 몇 번 편집했습니다 ...) – abarnert