文字列と整数からハッシュを作成する
-
06-07-2019 - |
質問
日食を覚えているし、その属性に基づいてオブジェクトのhashCodeを自動的に作成するテンプレートがあります。
数字と文字列を使用する場合の戦略の1つは次のようなものです。
return stringValue.hashCode() + intValue * 32;
そのようなものはありません。
手元に日食もアイデアもありません。そのような機能を作成したいと思います。
編集
このミニクラスを作成した回答に基づいて
class StringInt {
private final String s;
private final int i;
static StringInt valueOf( String string , int value ) {
return new StringInt( string, value );
}
private StringInt( String string, int value ) {
this.s = string;
this.i = value;
}
public boolean equals( Object o ) {
if( o != null && o instanceof StringInt ){
StringInt other = ( StringInt ) o;
return this.s == other.s && this.i == other.i;
}
return false;
}
public int hashCode() {
return s != null ? s.hashCode() * 37 + i : i;
}
}
このクラスは、大きなメモリマップ(> 10k要素)のキーとして使用されます。文字列とintが同じであるかどうかを確認するために毎回それらを繰り返したくありません。
ありがとう。
ps .. mmhおそらくStringIntKeyという名前にする必要があります。
解決
Apache Commons HashcodeBuilderを使用します:
public int hashCode() {
new HashCodeBuilder(17, 37).
append(myString).
append(myInt);
}
ここにリンク: http://commons.apache.org /lang/api-2.3/org/apache/commons/lang/builder/HashCodeBuilder.html
そしてここ:
http://www.koders.com/java/fidCE4E86F23847AE93909CE105394B668DDB0F491A.aspx aspa / p>
他のヒント
Eclipseは常にほぼ同じハッシュ関数を実行します。ここでは、フィールドとしてinおよびStringを持つクラスの例を示します
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + this.interger;
result = prime * result + ((this.string == null) ? 0 : this.string.hashCode());
return result;
}
これらは常に31を素数として選択し、次に、組み込みのハッシュ関数または値がプリミティブの場合は複数を選択します。このようなものをメソッドとして作成するのは難しくありません。
public int hashCode(Object ... things) {
final int prime = 31;
int result = 1;
for(Object thing : things) {
result = prime * result + thing.hashCode();
}
return result;
}
または、別のライブラリを追加したくない場合は、次のようにします:
public int hashCode() {
StringBuilder builder = new StringBuilder();
builder.append(myString);
builder.append(myInteger);
return builder.toString().hashCode();
}
ハッシュコードメソッドは、何度も呼び出される可能性があるため、最適化する価値があります。計算が複雑な場合は、ハッシュ値をメモすることを検討してください。また、必要以上の計算を必要とすることは避けてください。 (たとえば、StringBuilderソリューションは、ほとんどの時間を一時的な文字列の作成に費やします。)
他に指摘したいのは、ハッシュの品質が重要であることです。多くの共通キーをマップするハッシュコードアルゴリズムを避けたい。その場合、ハッシュテーブルルックアップはO(1)でなくなる可能性があります。 (最悪の場合、O(N)...つまり線形検索に相当します!)悪いハッシュ関数の例を次に示します。
int hashcode() {
int hash = 1;
for (int val : this.values) {
hash = hash * value;
}
return hash;
}
this.values
の要素がゼロの場合に何が起こるか考えてください...
java.util.Objects
パッケージの Objects
クラスを使用して、ハッシュコードをすばやく取得することもできます。
@Override
public int hashCode() {
return Objects.hash(this.string, this.integerValue, this.otherDataTypes);
}
最新の編集に加えて、ストレージの問題よりも検索速度が重要な場合は、 StringInt
クラスを構築するときにハッシュコードを事前に計算して保存できます。これは、 String
および int
フィールドを final
としてマークし、 String
が不変。
また、完全な比較を行う前に、比較対象のオブジェクトが== this
であることを確認することにより、 equals
メソッドを最適化できます。また、文字列フィールドを比較する前に、まず安価なintベースの比較を行うことをお勧めします。
別の最後の提案: valueOf(String、int)
メソッドを変更して、 StringInt
を構築するか、同じインスタンスが既に存在する場合は以前に作成したインスタンスを返すことができます String
およびint値。これにより、構築はより高価になりますが、" =="を使用して StringInt
を比較できるため、比較は非常に安価です。同じ String
と int
の値で2つの StringInt
が作成されることはないという知識がある。