두 문자열이 상호 교환 가능한 경우 두 문자열이있는 구조에 대해 GetHashCode를 어떻게 구현합니까?
C #에 구조가 있습니다.
public struct UserInfo
{
public string str1
{
get;
set;
}
public string str2
{
get;
set;
}
}
유일한 규칙은 UserInfo(str1="AA", str2="BB").Equals(UserInfo(str1="BB", str2="AA"))
이 구조에 대해 GetHashCode 함수를 재정의하는 방법은 무엇입니까?
MSDN :
해시 함수에는 다음 속성이 있어야합니다.
- 두 개체가 동일한 것으로 비교되는 경우
GetHashCode각 개체 의 메서드는 동일한 값을 반환해야합니다. 그러나 두 개체가 동일하게 비교되지 않으면 두 개체에 대한GetHashCode메서드가 다른 값을 반환 할 필요가 없습니다.GetHashCode개체의 방법은 지속적만큼 개체의 반환 값 결정 객체 상태에 아무런 변형이없는 동일한 해쉬 코드를 반환해야Equals방법. 이것은 현재 응용 프로그램 실행에 대해서만 적용되며 응용 프로그램이 다시 실행되면 다른 해시 코드가 반환 될 수 있습니다.- 최상의 성능을 위해 해시 함수는 모든 입력에 대해 무작위 분포를 생성해야합니다.
올바른 방법을 고려하는 것은 다음과 같습니다.
return str1.GetHashCode() ^ str2.GetHashCode()
^ 다른 교환 연산으로 대체 가능
Jon Skeet의 답변을 참조하십시오 -이진 연산 ^은 좋지 않으며 종종 충돌 해시를 생성합니다!
public override int GetHashCode()
{
unchecked
{
return (str1 ?? String.Empty).GetHashCode() +
(str2 ?? String.Empty).GetHashCode();
}
}
'+'연산자를 사용하는 것이 '^'를 사용하는 것보다 나을 수 있습니다. ( 'AA', 'BB')와 ( 'BB', 'AA')가 명시 적으로 동일하기를 원하지만 ( 'AA', 'AA') 및 ( 'BB', 'BB')는 동일해야합니다 (또는 해당 문제에 대해 모두 동일한 쌍).
null의 경우 알려진 상수를 즉시 반환하지 않고 빈 문자열에 대해 'GetHashCode ()'를 수행하기 때문에 '가능한 한 빨리'규칙은이 솔루션에서 완전히 준수되지 않지만 명시 적으로 측정하지 않아도 기꺼이 많은 null을 기대하지 않는 한 그 차이가 걱정할만큼 크지 않을 것이라고 추측하기 위해.
일반적으로 클래스에 대한 해시 코드를 생성하는 간단한 방법은 해시 코드 생성에 참여할 수있는 모든 데이터 필드를 XOR하는 것입니다 (다른 사람이 지적한대로 null을 확인하도록주의). 이것은 또한 UserInfo ( "AA", "BB") 및 UserInfo ( "BB", "AA")에 대한 해시 코드가 동일하다는 (인공?) 요구 사항을 충족합니다.
클래스 사용에 대한 가정을 할 수 있다면 해시 함수를 개선 할 수 있습니다. 예를 들어, str1과 str2가 같은 것이 일반적이라면 XOR은 좋은 선택이 아닐 수 있습니다. 그러나 str1과 str2가 이름과 성을 나타내는 경우 XOR은 아마도 좋은 선택 일 것입니다.
이것은 분명히 실제 예제는 아니지만 다음과 같은 점을 지적 할 가치가있을 수 있습니다.-이것은 아마도 구조체 사용의 좋지 않은 예일 것입니다 : 구조체는 일반적으로 값 의미 체계를 가져야합니다. 여기의 경우. -setter와 함께 속성을 사용하여 해시 코드를 생성하는 것도 문제를 요구합니다.
간단한 일반적인 방법은 다음과 같습니다.
return string.Format("{0}/{1}", str1, str2).GetHashCode();
엄격한 성능 요구 사항이없는 한 이것이 제가 생각할 수있는 가장 쉬운 방법이며 복합 키가 필요할 때이 방법을 자주 사용합니다. null케이스를 잘 처리하고 (일반적으로) 해시 충돌을 일으키지 않습니다. 문자열에 '/'가 필요하면 예상하지 않은 다른 구분 기호를 선택하십시오.
public override int GetHashCode()
{
unchecked
{
return(str1 != null ? str1.GetHashCode() : 0) ^ (str2 != null ? str2.GetHashCode() : 0);
}
}
ReSharper는 다음을 제안합니다.
public int GetHashCode()
{
unchecked
{
int hashCode;
// String properties
hashCode = (hashCode * 397) ^ (str1!= null ? str1.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (str2!= null ? str1.GetHashCode() : 0);
// int properties
hashCode = (hashCode * 397) ^ intProperty;
return hashCode;
}
}
397 is a prime of sufficient size to cause the result variable to overflow and mix the bits of the hash somewhat, providing a better distribution of hash codes. Otherwise there's nothing special in 397 that distinguishes it from other primes of the same magnitude.
Ah yes, as Gary Shutler pointed out:
return str1.GetHashCode() + str2.GetHashCode();
Can overflow. You could try casting to long as Artem suggested, or you could surround the statement in the unchecked keyword:
return unchecked(str1.GetHashCode() + str2.GetHashCode());
Try out this one:
(((long)str1.GetHashCode()) + ((long)str2.GetHashCode())).GetHashCode()
Many possibilities. E.g.
return str1.GetHashCode() ^ str1.GetHashCode()
Perhaps something like str1.GetHashCode() + str2.GetHashCode()? or (str1.GetHashCode() + str2.GetHashCode()) / 2? This way it would be the same regardless of whether str1 and str2 are swapped....
Sort them, then concatenate them:
return ((str1.CompareTo(str2) < 1) ? str1 + str2 : str2 + str1)
.GetHashCode();
GetHashCode's result is supposed to be:
- As fast as possible.
- As unique as possible.
Bearing those in mind, I would go with something like this:
if (str1 == null)
if (str2 == null)
return 0;
else
return str2.GetHashCode();
else
if (str2 == null)
return str1.GetHashCode();
else
return ((ulong)str1.GetHashCode() | ((ulong)str2.GetHashCode() << 32)).GetHashCode();
Edit: Forgot the nulls. Code fixed.
Too complicated, and forgets nulls, etc. This is used for things like bucketing, so you can get away with something like
if (null != str1) {
return str1.GetHashCode();
}
if (null != str2) {
return str2.GetHashCode();
}
//Not sure what you would put here, some constant value will do
return 0;
This is biased by assuming that str1 is not likely to be common in an unusually large proportion of instances.
'Nice programing' 카테고리의 다른 글
| 스크립트의 ggplot 플롯이 Rstudio에 표시되지 않습니다. (0) | 2020.11.14 |
|---|---|
| ES6 : 새 키워드없이 클래스 생성자 호출 (0) | 2020.11.14 |
| 목록에 추가하는 것이 왜 나쁜가요? (0) | 2020.11.14 |
| VB.net에서 C # '내부'란 무엇입니까? (0) | 2020.11.14 |
| IntelliJ에서 Java 클래스의 메서드를 재정렬하는 간단한 방법은 무엇입니까? (0) | 2020.11.14 |