假設您有一個字符串S和一個列表L中的數字序列,使得len(S)= len(L)。查找字符和數字之間可能的雙射
檢查是否可以在字符串中的字符與序列中的數字之間找到雙射,以便每個字符與唯一的一個數字相匹配,最乾淨的方法是什麼?
例如,「爲aabbcc」應與115522而不是123456或111111
我有兩個類型的字典和迴路複雜的設置,但我不知道是否有這樣做的清潔方式,也許通過使用Python庫中的一些函數。
假設您有一個字符串S和一個列表L中的數字序列,使得len(S)= len(L)。查找字符和數字之間可能的雙射
檢查是否可以在字符串中的字符與序列中的數字之間找到雙射,以便每個字符與唯一的一個數字相匹配,最乾淨的方法是什麼?
例如,「爲aabbcc」應與115522而不是123456或111111
我有兩個類型的字典和迴路複雜的設置,但我不知道是否有這樣做的清潔方式,也許通過使用Python庫中的一些函數。
我會使用一組這樣的:
In [9]: set("aabbcc")
Out[9]: set(['a', 'c', 'b'])
In [10]: set(zip("aabbcc", [1, 1, 5, 5, 2, 2]))
Out[10]: set([('a', 1), ('c', 2), ('b', 5)])
第二組將具有長度等於當且僅當該映射是滿射的第一組。 (如果不是,你將有一個字母映射的兩個副本在第二組相同的號碼,或反之亦然)
這裏是實現這個想法
def is_bijection(seq1, seq2):
distinct1 = set(seq1)
distinct2 = set(seq2)
distinctMappings = set(zip(seq1, seq2))
return len(distinct1) == len(distinctMappings) and len(distinct2) == len(distinctMappings)
這也將返回代碼如果一個序列比另一個短,但是有效的映射已經建立,則爲true。如果序列長度必須相同,則應該爲此添加檢查。
嗯,我不相信這個作品?用[1,1,1,1,1,1]結束(a,1),(b,1),(c,1),它有3個項目,就像另一個集合一樣。 所以這給你一個投射,而不是一個完整的雙射。 –
是的。我最初只是提供了這個想法。編輯版本中的代碼檢查兩個集合。 – acjay
快速偏離主題的問題是'a == b == c'被認爲是不好的做法? –
import itertools
a = 'aabbcc'
b = 112233
z = sorted(zip(str(a), str(b)))
x = all(
gx == g0
for k, g in itertools.groupby(z, key=lambda x: x[0])
for gx in g for g0 in g
)
print x
或:
import itertools
a = 'aabbcc'
b = 112233
z = zip(str(a), str(b))
x = all(
(z1[0] == z2[0]) == (z1[1] == z2[1]) for z1 in z for z2 in z
)
print x
有一個更優雅的方式來做到這一點(與排序和itertools.groupby
),但我wayy睡覺,deproved明白這一點現在。但是,這應該仍然工作:
In [172]: S = "aabbcc"
In [173]: L = [1, 1, 5, 5, 2, 2]
In [174]: mapping = collections.defaultdict(list)
In [175]: reverseMapping = collections.defaultdict(list)
In [176]: for digit, char in zip(L, S):
mapping[digit].append(char)
reverseMapping[char].append(digit)
.....:
In [177]: all(len(set(v))==1 for v in mapping.values()) and all(len(set(v))==1 for v in reverseMapping.values())
Out[177]: True
In [181]: S = "aabbcc"
In [182]: L = [1, 2, 3, 4, 5, 6]
In [183]: mapping = collections.defaultdict(list)
In [184]: reverseMapping = collections.defaultdict(list)
In [185]: for digit, char in zip(L, S):
mapping[digit].append(char)
reverseMapping[char].append(digit)
.....:
In [186]: all(len(set(v))==1 for v in mapping.values()) and all(len(set(v))==1 for v in reverseMapping.values())
Out[186]: False
希望這有助於
這尊重順序:
>>> s = "aabbcc"
>>> n = 115522
>>> l1 = dict(zip(s, str(n))).items()
>>> l2 = zip(s, str(n))
>>> l1
[('a', '1'), ('c', '2'), ('b', '5')]
>>> l2
[('a', '1'), ('a', '1'), ('b', '5'), ('b', '5'), ('c', '2'), ('c', '2')]
>>> not bool([i for i in l2 if i not in l1])
True
>>> n = 115225
>>> l1 = dict(zip(s, str(n))).items()
>>> l2 = zip(s, str(n))
>>> not bool([i for i in l2 if i not in l1])
False
既然你通常只說說集之間的雙射,我想,不像其他的答案,數字的訂單不需要匹配字母的順序。如果是這樣,有一個簡短而優雅的解決方案,但它需要python 2.7中引入的collections.Counter
類。對於那些使用舊版本的用戶,有一個backport for 2.5+。
from collections import Counter
def bijection_exists_between(a, b):
return sorted(Counter(a).values()) == sorted(Counter(b).values())
測試:
>>> bijection_exists_between("aabbcc", "123123")
True
>>> bijection_exists_between("aabbcc", "123124")
False
你的例子是在邊緣情況相當輕,因爲讀了你的問題的另一種方式允許的位數和字母數量不相等(即你看對於從一組唯一字符到一組唯一數字的雙射,因此例如"aabbcc"
將會偏移到"123333"
。)。如果這是您的意思,請使用此版本代替:
def bijection_exists_between(a, b):
return len(set(a)) == len(set(b))
也許我還不清楚,雙色注射是雙向映射。在你的最後一個例子中,'a'映射到1和2,其中3映射到'b'和'c',所以不僅它不是雙射的,它甚至不是雙射或內射的。 –
@EhsanKia你正在以一種奇怪的方式使用術語* bijection *。雙向映射是雙向映射,但它只存在於[sets](http://en.wikipedia.org/wiki/Set_(mathematics))之間。字符串不是一個集合,因爲它可能包含重複的值。所以要回答你的問題需要解釋,我已經提出了兩個完全有效的解釋。我的最後一個例子是雙向注入,即從「aabbcc」({a,b,c})中的一組字符到'123333'中的一組數字({1,2,3} })。 –
如果a =「abcabc」和b =「123127」預期的輸出是什麼?對或錯 – raton
錯誤,因爲'c'映射到3和7(或者另一種方式,3和7都映射到'c')。在雙射中,每個元素在另一個集合中只有一個匹配元素。 –