web-dev-qa-db-ja.com

一意の文字列から一意のintを生成するにはどうすればよいですか?

一意のIDを保持する文字列を持つオブジェクトがあります。 ( "ocx7gf"や "67hfs8"など)明らかに一意になるint hascode()の実装を提供する必要があります。

最も簡単/最速の方法で文字列を一意のintにキャストするにはどうすればよいですか?

10倍。

編集-OK。 String.hashcodeが可能であることはすでに知っています。ただし、どの場所でも推奨されません。実際には、他の方法が推奨されていない場合-コレクションにオブジェクトがあり、ハッシュコードが必要な場合、それを使用するかどうか。それを別の文字列に連結してより成功させる必要がありますか?

16
Bick

いいえ、実装の大部分が壊れていることは明らかであるため、「明らかに」一意の値を返す実装が必要です必要はありません

あなたがしたいことは、特に一般的な値(他の値よりも一般的な値がある場合)について、ビット全体に適切に分散させることです。形式の特別な知識がない限り、文字列自体のハッシュコードを使用するのが最善です。

Id形式の制限についての特別な知識があれば、誤った仮定により状況が悪化する可能性が高くなりますが、カスタマイズしてパフォーマンスを向上させることができる場合があります。

編集:ビットの適切な拡散について。

ここや他の回答で述べたように、完全に一意であることは不可能であり、ハッシュの衝突が発生する可能性があります。ハッシュを使用するメソッドはこれを知っており、それを処理できますが、パフォーマンスに影響を与えるを行うため、衝突はまれです。

さらに、ハッシュは一般に再ハッシュされるため、32ビットの数値は、たとえば0から22の範囲の1つであり、その範囲内で可能な限り良好な分布を求めています。

また、ハッシュの計算にそれほど時間がかからず、それ自体がボトルネックになることとのバランスをとりたいと考えています。不完全なバランスをとる行為。

悪いハッシュ法の典型的な例は、X、Y整数の座標ペアの例です。

return X ^ Y;

これは4 ^ 32の可能な入力から2 ^ 32の可能な値を返すのに最適ですが、実際の使用では、XとYが等しい({0、0}、{1 、1}、{2、2}など)すべてがゼロにハッシュされるか、一致するペア({2、3}と{3、2})が同じ数にハッシュされます。以下のサービスが提供される可能性があります。

return ((X << 16) | (x >> 16)) ^ Y;

さて、areは、前者よりも恐ろしいほど多くの可能な値ですが、実際のケースではよりよく機能する傾向があります。

もちろん、汎用クラスを作成している場合(考えられる入力の種類がわからない場合)、または目的をよりよく理解している場合は、別の仕事があります。たとえば、Dateオブジェクトを使用していて、すべてが日付のみ(時間の部分は常に午前0時)であり、互いに数年以内であることがわかっている場合は、日、月、日のみを使用したカスタムハッシュコードを使用できます。年の下位桁、標準の桁より上。 Dateの作者は、そのような知識に取り組むことができず、誰もが満足できるようにしなければなりません。

したがって、たとえば、指定された文字列が常に[az]または[0-9]の範囲の6つの大文字と小文字を区別しない文字で構成されることがわかっている場合(これはあなたのように見えますが、質問から明らかではありません)それはそうです)そして私は各文字に0から35までの値(各文字に対して36の可能な値)を割り当てたアルゴリズムを使用し、次に現在の値に36を乗算し、次の文字。

Idが適切に分散していると仮定すると、これは特に適切な方法です。特に、ハッシュの下位桁がidで最も頻繁に変更される文字と一致するように注文した場合(このような呼び出しが行われた場合) 、したがって、より小さな範囲への再ハッシュをうまく生き残っています。

ただし、確かにそのような形式の知識がないため、確実にその呼び出しを行うことはできず、事態を悪化させる可能性があります(ハッシュ品質の向上がほとんどまたはまったくない場合は、アルゴリズムが遅くなります)。

あなたが持っている1つの利点は、それ自体がIDであるため、おそらく他の等しくないオブジェクトが同じIDを持っていないため、他のプロパティを調べる必要がないことです。これは常に成立するとは限りません。

23
Jon Hanna

長さが無制限の文字列から一意の整数を取得することはできません。 40億個(2 ^ 32)の一意の整数がありますが、一意の文字列の数はほとんど無限です。

String.hashCode()は一意の整数を提供しませんが、入力文字列に基づいて異なる結果を提供するために最善を尽くします。

[〜#〜]編集[〜#〜]

編集した質問では、String.hashCode()は推奨されていません。これは当てはまりません。特別な理由がない限り、使用しないことをお勧めします。特別な理由がある場合は、詳細をお知らせください。

11
Jon Bright

そこには36を底とする数値(a-z + 0-9)があるようです。 Integer.parseInt(s, 36)を使用してintに変換しませんか?明らかに、一意のIDが多すぎると、intに収まりませんが、その場合、一意の整数では運が悪くなるため、String.hashCode()を使用して取得する必要があります、ユニークに近づくために最善を尽くします。

6
Jonathan

文字列が何らかの方法で制限されているか、整数が変換しようとしている文字列よりも多くのビットを保持している場合を除き、一意性を保証することはできません。

文字列に32ビット整数と64文字の文字セットがあるとします。つまり、1文字あたり6ビットです。これにより、整数に5文字を格納できます。それ以上だと収まりません。

4
paxdiablo

これを行う1つの方法は、各文字に値を割り当て、文字列の各場所に複数の値を割り当てることです(つまり、a = 1、b = 2など)。最初の桁のすべて(左から右に読む)が乗算されます。素数、次は次の素数、というように、最後の桁は、その桁の可能なサブセットの数より大きい素数で乗算されます(スペースの場合は26 + 1、キャピトルの場合は52 + 1など)。その他のサポートされている文字)。数値が最初の数字(左端の文字)にマップされる場合、最初の文字が何であれ、一意の文字列から1または6にマッピングして生成する任意の数値は、一意の値を提供します。

犬は30,3(15)、101(7)または782ですが、神33,3(15)、101(4)または482です。生成される一意の文字列よりも重要なのは、元の数字が30(782)は12(782)に固有のものであり、独自の可能性を何とかして乗り越えた場合、同様の文字列を区別するために使用されます。犬は常に犬ですが、猫やマウスになることはありません。

0

各文字列文字を5桁の2進数で表します。 a by 00001 b by 00010など。したがって、32の組み合わせが可能です。たとえば、catは00100 00001 01100と書かれ、このバイナリを10進数に変換します。これは4140なので、猫は4140になります。同様に、猫を最初にバイナリに変換し、5桁のバイナリを文字列にマッピングすることで、猫を4140から戻すことができます。

0
Abhishek