[英]Python - partitioning a list of strings using an equivalence relation
我有一個字母字符串列表[str1,str2,...]
,我需要使用等價關系R划分為等價類,其中,如果可以通過str1
的序列從str1
獲得str2
,則str1 R str2
(以關系符號表示)。有效的單字母更改,其中“有效”表示它產生有效的字母單詞,例如cat --> 'cax
cat --> car
有效,而cat --> 'cax
無效。 如果輸入列表為['cat','ace','car','zip','ape','pip']
則代碼應返回[['cat','car'],['ace','ape'],['zip','pip']]
。
我有一個初始的工作版本,但是,它會產生一些包含重復項的“類”。
我不認為有任何Python包可以讓我定義這種等價關系,但即使如此,最好的方法是什么?
應該適用於不同長度的字符串。 顯然,訂購很重要。
def is_one_letter_different(s1, s2):
if len(s1) != len(s2):
return False
diff_count = 0;
for char1, char2 in zip(s1, s2):
if char1 != char2:
diff_count += 1
return diff_count == 1
def group(candidates):
groups = []
for candidate in candidates:
for group in groups:
for word in group:
if is_one_letter_different(word, candidate):
group.append(candidate)
break
if candidate in group:
break
else:
groups.append([candidate])
return groups
print group(['bread','breed', 'bream', 'tread', 'treat', 'short', 'shorn', 'shirt', 'shore', 'store','eagle','mired', 'sired', 'hired'])
輸出:
[['bread', 'breed', 'bream', 'tread', 'treat'], ['short', 'shorn', 'shirt', 'shore', 'store'], ['eagle'], ['mired', 'sired', 'hired']]
編輯:更新以遵循其他測試用例。 我不確定輸出是否正確-請驗證。 並在下次為我們提供良好的測試用例。
我會做這樣的事情:構造一個無向圖,其中每個詞都是一個節點,每個邊都表明它們之間的關系。 然后,您可以識別圖中的每個斷開的“島”,每個島都代表一個等價類。
from collections import defaultdict
def exactly_one(iter):
count = 0
for x in iter:
if x:
count += 1
if count > 1:
break
return count == 1
def are_one_letter_apart(a,b):
if len(a) != len(b): return False
return exactly_one(a_char != b_char for a_char, b_char in zip(a,b))
def pairs(seq):
for i in range(len(seq)):
for j in range(i+1, len(seq)):
yield (seq[i], seq[j])
def search(graph, node):
seen = set()
to_visit = set()
to_visit.add(node)
while to_visit:
cur = to_visit.pop()
if cur in seen: continue
for neighbor in graph[cur]:
if neighbor not in seen:
to_visit.add(neighbor)
seen.add(cur)
return seen
def get_islands(graph):
seen = set()
islands = []
for item in graph.iterkeys():
if item in seen: continue
group = search(graph, item)
seen = seen | group
islands.append(group)
return islands
def create_classes(seq, f):
graph = defaultdict(list)
for a,b in pairs(seq):
if f(a,b):
graph[a].append(b)
graph[b].append(a)
#one last pass to pick up items with no relations to anything else
for item in seq:
if item not in graph:
graph[item].append(item)
return [list(group) for group in get_islands(graph)]
seq = ['cat','ace','car','zip','ape','pip']
print create_classes(seq, are_one_letter_apart)
結果:
[['ace', 'ape'], ['pip', 'zip'], ['car', 'cat']]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.