簡體   English   中英

Python-使用等價關系對字符串列表進行分區

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM