[英]Average of two strings in alphabetical/lexicographical order
假設你取字符串'a'和'z'並按字母順序列出它們之間的所有字符串:['a','b','c'...'x','y','z “]。 從這個列表的中點開始,你會發現'm'。 所以這有點像取兩個字符串的平均值。
您可以將其擴展為具有多個字符的字符串,例如,'aa'和'zz'之間的中點可以在列表中間找到['aa','ab','ac'...'zx ','zy','zz']。
可能在某處有一個Python方法可以做到這一點嗎? 如果沒有,即使知道算法的名稱也會有所幫助。
我開始制作我自己的例程,簡單地通過兩個字符串並找到第一個不同字母的中點,這似乎在'aa'和'az'中點是'am'時效果很好,但是然后它在'cat'上失敗了,它認為是'c'的'小狗'中點。 我嘗試使用谷歌搜索“二進制搜索字符串中點”等但不知道我在這里嘗試做什么的名稱我沒有運氣。
我添加了自己的解決方案作為答案
如果您定義字符字母,您只需轉換為基數10,執行平均值,然后轉換回base-N,其中N是字母表的大小。
alphabet = 'abcdefghijklmnopqrstuvwxyz'
def enbase(x):
n = len(alphabet)
if x < n:
return alphabet[x]
return enbase(x/n) + alphabet[x%n]
def debase(x):
n = len(alphabet)
result = 0
for i, c in enumerate(reversed(x)):
result += alphabet.index(c) * (n**i)
return result
def average(a, b):
a = debase(a)
b = debase(b)
return enbase((a + b) / 2)
print average('a', 'z') #m
print average('aa', 'zz') #mz
print average('cat', 'doggie') #budeel
print average('google', 'microsoft') #gebmbqkil
print average('microsoft', 'google') #gebmbqkil
編輯 :根據評論和其他答案,您可能希望通過將字母表的第一個字母附加到較短的單詞來處理不同長度的字符串,直到它們的長度相同。 這將導致兩個輸入之間的“平均”以字典順序排列。 下面的代碼更改和新輸出。
def pad(x, n):
p = alphabet[0] * (n - len(x))
return '%s%s' % (x, p)
def average(a, b):
n = max(len(a), len(b))
a = debase(pad(a, n))
b = debase(pad(b, n))
return enbase((a + b) / 2)
print average('a', 'z') #m
print average('aa', 'zz') #mz
print average('aa', 'az') #m (equivalent to ma)
print average('cat', 'doggie') #cumqec
print average('google', 'microsoft') #jlilzyhcw
print average('microsoft', 'google') #jlilzyhcw
它聽起來像你想要的,是將字母字符視為0和1之間的基數為26的值。如果你有不同長度的字符串(基數為10的例子),比如305和4202,那么你的中間點是3,因為你一次只看一個角色。 相反,將它們視為浮點尾數:0.305和0.4202。 從中可以很容易地得出.3626的中點(如果你願意的話你可以圓)。
對基數26(a = 0 ... z = 25,ba = 26,bb = 27等)做同樣的事情來計算字母:
貓成為'a.cat'而小狗成為'a.doggie',做數學給貓的小數值為0.078004096,小狗的值為0.136390697,平均值為0.107197397,其中26基本上是“cumcqo”
如果您的意思是按字母順序排列,只需使用FogleBird的算法,但反轉參數和結果!
>>> print average('cat'[::-1], 'doggie'[::-1])[::-1]
cumdec
或者像這樣重寫平均值
>>> def average(a, b):
... a = debase(a[::-1])
... b = debase(b[::-1])
... return enbase((a + b) / 2)[::-1]
...
>>> print average('cat', 'doggie')
cumdec
>>> print average('google', 'microsoft')
jlvymlupj
>>> print average('microsoft', 'google')
jlvymlupj
根據您的建議用法,一致哈希( http://en.wikipedia.org/wiki/Consistent_hashing )似乎更有意義。
感謝所有回答的人,但我最終編寫了自己的解決方案,因為其他人並不是我所需要的。 我試圖平均應用程序引擎密鑰名稱,並在研究了它們之后我發現它們實際上允許名稱中的任何7位ASCII字符。 另外,我真的不能依賴將鍵名首先轉換為浮點的解決方案,因為我懷疑浮點精度是不夠的。
要取平均值,首先將兩個數字相加,然后除以2。 這些都是如此簡單的操作,我決定只添加函數來添加和划分表示為列表的基數128。 這個解決方案尚未在我的系統中使用,所以我可能仍然會發現其中的一些錯誤。 它也可能短得多,但這只是我需要完成的事情,而不是試圖讓它完美。
# Given two lists representing a number with one digit left to decimal point and the
# rest after it, for example 1.555 = [1,5,5,5] and 0.235 = [0,2,3,5], returns a similar
# list representing those two numbers added together.
#
def ladd(a, b, base=128):
i = max(len(a), len(b))
lsum = [0] * i
while i > 1:
i -= 1
av = bv = 0
if i < len(a): av = a[i]
if i < len(b): bv = b[i]
lsum[i] += av + bv
if lsum[i] >= base:
lsum[i] -= base
lsum[i-1] += 1
return lsum
# Given a list of digits after the decimal point, returns a new list of digits
# representing that number divided by two.
#
def ldiv2(vals, base=128):
vs = vals[:]
vs.append(0)
i = len(vs)
while i > 0:
i -= 1
if (vs[i] % 2) == 1:
vs[i] -= 1
vs[i+1] += base / 2
vs[i] = vs[i] / 2
if vs[-1] == 0: vs = vs[0:-1]
return vs
# Given two app engine key names, returns the key name that comes between them.
#
def average(a_kn, b_kn):
m = lambda x:ord(x)
a = [0] + map(m, a_kn)
b = [0] + map(m, b_kn)
avg = ldiv2(ladd(a, b))
return "".join(map(lambda x:chr(x), avg[1:]))
print average('a', 'z') # m@
print average('aa', 'zz') # n-@
print average('aa', 'az') # am@
print average('cat', 'doggie') # d(mstr@
print average('google', 'microsoft') # jlim.,7s:
print average('microsoft', 'google') # jlim.,7s:
import math
def avg(str1,str2):
y = ''
s = 'abcdefghijklmnopqrstuvwxyz'
for i in range(len(str1)):
x = s.index(str2[i])+s.index(str1[i])
x = math.floor(x/2)
y += s[x]
return y
print(avg('z','a')) # m
print(avg('aa','az')) # am
print(avg('cat','dog')) # chm
還在處理不同長度的字符串...任何想法?
這個版本認為'abc'是一個像0.abc的分數。 在這種方法中,空間為零並且是有效的輸入/輸出。
MAX_ITER = 10
letters = " abcdefghijklmnopqrstuvwxyz"
def to_double(name):
d = 0
for i, ch in enumerate(name):
idx = letters.index(ch)
d += idx * len(letters) ** (-i - 1)
return d
def from_double(d):
name = ""
for i in range(MAX_ITER):
d *= len(letters)
name += letters[int(d)]
d -= int(d)
return name
def avg(w1, w2):
w1 = to_double(w1)
w2 = to_double(w2)
return from_double((w1 + w2) * 0.5)
print avg('a', 'a') # 'a'
print avg('a', 'aa') # 'a mmmmmmmm'
print avg('aa', 'aa') # 'a zzzzzzzz'
print avg('car', 'duck') # 'cxxemmmmmm'
不幸的是,天真的算法無法檢測周期性的'z',這可能是十進制的0.99999; 因此'zzzzzzzz'實際上是'aa'('z'周期之前的空間必須加1。
為了規范化,可以使用以下功能
def remove_z_period(name):
if len(name) != MAX_ITER:
return name
if name[-1] != 'z':
return name
n = ""
overflow = True
for ch in reversed(name):
if overflow:
if ch == 'z':
ch = ' '
else:
ch=letters[(letters.index(ch)+1)]
overflow = False
n = ch + n
return n
print remove_z_period('a zzzzzzzz') # 'aa'
我有一段時間沒有在python中編程,這看起來很有趣。 忍受我的遞歸編程。 太多的函數式語言看起來像python。
def stravg_half(a, ln):
# If you have a problem it will probably be in here.
# The floor of the character's value is 0, but you may want something different
f = 0
#f = ord('a')
L = ln - 1
if 0 == L:
return ''
A = ord(a[0])
return chr(A/2) + stravg_half( a[1:], L)
def stravg_helper(a, b, ln, x):
L = ln - 1
A = ord(a[0])
B = ord(b[0])
D = (A + B)/2
if 0 == L:
if 0 == x:
return chr(D)
# NOTE: The caller of helper makes sure that len(a)>=len(b)
return chr(D) + stravg_half(a[1:], x)
return chr(D) + stravg_helper(a[1:], b[1:], L, x)
def stravg(a, b):
la = len(a)
lb = len(b)
if 0 == la:
if 0 == lb:
return a # which is empty
return stravg_half(b, lb)
if 0 == lb:
return stravg_half(a, la)
x = la - lb
if x > 0:
return stravg_helper(a, b, lb, x)
return stravg_helper(b, a, la, -x) # Note the order of the args
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.