2012-04-26 98 views
1

我有一大組名稱(數以百萬計)。他們每個人都有一個名字,一個可選的中間名和一個姓氏。我需要將這些名稱編碼爲唯一代表名稱的數字。編碼應該是一對一的,即一個名字只能與一個數字相關聯,而一個數字只能與一個名字相關聯。將名稱字符串編碼爲唯一編號

什麼是對此進行編碼的智能方式?我知道根據它在字母集中的位置(a-> 1,b-> 2 ...等)標記每個字母的名稱很容易,所以像Deepa這樣的名字會得到 - > 455161,但是再次在這裏,我不能說如果'16'是真的16或1和6的組合。

所以,我正在尋找一種智能的編碼方式。

此外,編碼應該是這樣的,即任何名字的輸出數字中的數字的數量應該具有固定的數字位數,即它應該與長度無關。這可能嗎?

感謝 阿布舍克小號

+1

這不會解決固定長度的問題,但你可以將每個字母編碼爲2個數字:a = 01,b = 02 .... j = 10,k = 11 ... z = 26。做這種轉換的重點是什麼?可能有更好的解決方案。另外,你可能提出的任何哈希函數*將會在某個點發生碰撞(即,不嚴格爲1:1)。爲什麼不能只用一個序列號的數據庫表作爲關聯名稱的關鍵字?隨着新名字的出現,只需查找它們即可找到它們的關鍵字,如果沒有的話就添加它們。 – NealB 2012-04-26 18:07:09

+0

你需要解釋更多關於你的動機。天真地說,您可以簡單地將名稱的utf-8表示作爲(非常大的)base-256數字;翻譯成你喜歡的任何基地 - 但這是非常無用的。如果您只需要每個名稱的唯一標識符,那麼數據庫可能是您的最佳選擇。 – 2012-04-27 01:34:01

+0

目標是能夠在3D維度空間中的其中一個維度上繪製名稱,其中另外兩個維度本質上已經是數字。因此,由於名稱本質上是文本的,因此我們需要在將它們繪製之前將名稱轉換爲數字。 – 2012-04-27 03:55:33

回答

2

你正在嘗試做的居然還有散列(至少如果你有數字的固定數量)。有一些很好的散列算法,幾乎沒有碰撞。例如,試用sha1,其中一個已經過很好的測試,可用於現代語言(請參閱http://en.wikipedia.org/wiki/Sha1) - 它對git來說似乎足夠好,所以它可能適用於您。

對於兩個不同的名字,當然存在相同散列值的小可能性,但散列總是如此,並且可以被照顧。使用sha1等,你不會有任何明顯的名稱和ID之間的聯繫,這可能是一個好的或壞的事情,這取決於你的問題。

如果您確實需要唯一的ID,您需要像NealB建議的那樣做一些事情,自己創建ID並在數據庫中連接名稱和ID(您可以隨機創建它們並檢查衝突或增加它們,從0000000000001左右)。 (給它一些思考和閱讀的第一個意見後改進答案)

+0

如果您想將答案限制在固定的位數,這是最好的方法。否則,以基數26整數實施它們。 – sukunrt 2012-04-26 18:05:15

+0

不,他要求1:1的映射,這是_not_散列。 – 2012-04-27 01:32:33

+0

但是從名字中計算一個值並要求一個固定長度的值會讓我在你看來有散列(至少當名字的長度沒有限制時) – kratenko 2012-04-27 11:26:34

0

您可以翻譯它,如果每一個字符(加空,至少)將佔據一個位置。

因此ABC,這是1,2,3已被翻譯成

1*(2*26+1)² + 2*(53) + 3 

通過這種方式,你可以編碼任意字符串,但如果輸入的長度不限(又該如何它?),你不能保證長度的上限。

5

爲了獲得相同的寬度數字,你不能只在零左墊?

一些選項:

  1. 排序。數它們。第10個名稱是數字10.
  2. 將每個字符視爲基數26(不區分大小寫,無 數字)或52(大小寫無數字)或36(數字不區分大小寫 )或62(大小寫數字敏感)編號。計算int中的 值。EG,名稱爲「abc」,您將有0 * 26^2 + 1 * 26^1 + 2 * 20^0。有時中文名字可能會用數字來表示音調。
  3. 使用「完美哈希」方案:http://en.wikipedia.org/wiki/Perfect_hash_function
  4. 這個主要建議在樂趣:使用goedel編號:)。所以 「abc」將是2^0 * 3^1 * 5^2 - 它是質數的乘積。 將因數分解可讓您恢復字符。數字 可能會變得相當大,但。
  5. 如果您還沒有使用它,轉換爲ASCII。然後將每個字符的 序號作爲基數爲256的編號系統中的數字。所以「abc」是0 * 256^2 + 1 * 256^1 + 2 * 256^0。

如果您需要能夠隨時更新您的姓名和號碼列表,#2,#4和#5應該可以工作。 #1和#3會有問題。 #5可能是未來最好的,儘管你可能會發現你需要在某些時候使用unicode。

我相信你可以做的Unicode爲#5變體中,2^32,而不是2^8 = =的權力256

+0

#5幫我解決了我的問題,謝謝。 – 2016-04-05 00:10:34

1

我一直在尋找一個解決方案,以非常相似的問題你提出的,這是我想出的:

def hash_string(value): 
    score = 0 
    depth = 1 
    for char in value: 
     score += (ord(char)) * depth 
     depth /= 256. 
    return score 

如果你不熟悉Python,這是它的作用。

  1. 比分是最初爲0和深度被設定爲1
  2. 對於每一個字符添加ord值*
    1. ord函數返回UTF-8值(0-255)的深度每個字符
    2. 然後它乘以「深度」。
  3. 最後深度由256

劃分從本質上講,它的工作方式是,最初的角色增加更多的得分,而後來的字符貢獻越來越少。如果你需要一個整數,把最終分數乘以2 ** 64。否則,你將有一個0-256之間的小數值。該編碼方案適用於二進制數據,並且byte/char中只有256個可能的值。

此方法適用於較小的字符串值,但對於較長的字符串,您會注意到十進制值需要比常規雙精度值(64位)更高的精度。在Java中,您可以使用'BigDecimal'並在Python中使用'decimal'模塊以提高精度。使用此方法的好處是返回的值是按排序順序排列的,因此可以「高效」地搜索它們。

2

可以使用BigInteger編碼任意的字符串是這樣的:

BigInteger bi = new BigInteger("some string".getBytes()); 

併爲獲取字符串後面使用:

String str = new String(bi.toByteArray());