Dictionary.TryGetValue 메서드 의 MSDN 항목에서 :
이 메서드는 ContainsKey 메서드의 기능과 Item 속성을 결합합니다.
키를 찾을 수 없으면 값 매개 변수는 값 유형 TValue에 적절한 기본값을 가져옵니다. 예를 들어 정수 유형의 경우 0, 부울 유형의 경우 false, 참조 유형의 경우 null입니다.
코드에서 사전에없는 키에 자주 액세스하려고하면 TryGetValue 메서드를 사용하십시오. 이 메소드를 사용하면 Item 속성에서 발생하는 KeyNotFoundException을 잡는 것보다 효율적입니다.
이 방법은 O (1) 연산에 접근합니다.
설명에서 ContainsKey를 호출 한 다음 조회를 수행하는 것보다 더 효율적이거나 더 편리한 지 명확하지 않습니다. 구현은 TryGetValue
ContainsKey를 호출 한 다음 Item을 호출 합니까 아니면 단일 조회를 수행하는 것보다 실제로 더 효율적입니까?
다시 말해,보다 효율적인 것은 무엇입니까 (즉, 어느 것이 더 적은 조회를 수행 하는가) :
Dictionary<int,int> dict;
//...//
int ival;
if(dict.ContainsKey(ikey))
{
ival = dict[ikey];
}
else
{
ival = default(int);
}
또는
Dictionary<int,int> dict;
//...//
int ival;
dict.TryGetValue(ikey, out ival);
참고 : 나는 벤치 마크를 찾고 있지 않습니다!
답변
TryGetValue
더 빠를 것입니다.
ContainsKey
TryGetValue
내부적으로 실제 입력 위치를 나타내는와 동일한 검사를 사용합니다 . 이 Item
속성은 실제로 TryGetValue
false와 같은 예외를 throw한다는 점을 제외하고는 코드 기능과 거의 동일합니다 .
ContainsKey
그 다음에 Item
기본적으로 사용 되는 조회 기능이 복제되며,이 경우 대부분의 계산이 수행됩니다.
답변
빠른 벤치 마크는 TryGetValue
약간의 우위를 보여줍니다 .
static void Main() {
var d = new Dictionary<string, string> {{"a", "b"}};
var start = DateTime.Now;
for (int i = 0; i != 10000000; i++) {
string x;
if (!d.TryGetValue("a", out x)) throw new ApplicationException("Oops");
if (d.TryGetValue("b", out x)) throw new ApplicationException("Oops");
}
Console.WriteLine(DateTime.Now-start);
start = DateTime.Now;
for (int i = 0; i != 10000000; i++) {
string x;
if (d.ContainsKey("a")) {
x = d["a"];
} else {
x = default(string);
}
if (d.ContainsKey("b")) {
x = d["b"];
} else {
x = default(string);
}
}
}
이것은 생산
00:00:00.7600000
00:00:01.0610000
제작 ContainsKey + Item
40 % 느린 안타 미스의도 조화를 가정에 대한 액세스를.
또한 프로그램을 항상 그리워 (즉, 항상 찾고 "b"
) 변경하면 두 버전이 똑같이 빨라집니다.
00:00:00.2850000
00:00:00.2720000
그러나 내가 “모든 히트”를 할 때, TryGetValue
여전히 확실한 승자입니다.
00:00:00.4930000
00:00:00.8110000
답변
지금까지 답변 중 어느 것도 실제로 질문에 대답하지 않았으므로 다음은 몇 가지 연구 후에 찾은 수용 가능한 답변입니다.
TryGetValue를 디 컴파일하면 다음을 수행하는 것을 볼 수 있습니다.
public bool TryGetValue(TKey key, out TValue value)
{
int index = this.FindEntry(key);
if (index >= 0)
{
value = this.entries[index].value;
return true;
}
value = default(TValue);
return false;
}
ContainsKey 메소드는 다음과 같습니다.
public bool ContainsKey(TKey key)
{
return (this.FindEntry(key) >= 0);
}
따라서 TryGetValue는 ContainsKey와 항목이있는 경우 배열 조회입니다.
TryGetValue는 ContainsKey + Item 조합보다 거의 두 배 빠릅니다.
답변
무슨 상관이야 🙂
아마도 TryGetValue
사용 하기 가 어려우므로 아마도 확장 방법으로 캡슐화하십시오.
public static class CollectionUtils
{
// my original method
// public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key)
// {
// V ret;
// bool found = dic.TryGetValue(key, out ret);
// if (found)
// {
// return ret;
// }
// return default(V);
// }
// EDIT: one of many possible improved versions
public static TValue GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key)
{
// initialized to default value (such as 0 or null depending upon type of TValue)
TValue value;
// attempt to get the value of the key from the dictionary
dictionary.TryGetValue(key, out value);
return value;
}
그런 다음 전화하십시오.
dict.GetValueOrDefault("keyname")
또는
(dict.GetValueOrDefault("keyname") ?? fallbackValue)
답변
왜 테스트하지 않습니까?
그러나 TryGetValue
한 번만 조회하기 때문에 더 빠릅니다. 물론 이것은 보장되지 않습니다. 즉, 구현마다 성능 특성이 다를 수 있습니다.
사전을 구현하는 방법 Find
은 항목의 슬롯을 찾는 내부 함수를 만든 다음 나머지를 빌드하는 것입니다.
답변
지금까지의 모든 대답은 훌륭하지만 중요한 요점을 그리워합니다.
API 클래스 (예 : .NET 프레임 워크)에 대한 메소드는 인터페이스 정의 (C # 또는 VB 인터페이스가 아니라 컴퓨터 과학 의미의 인터페이스)의 일부를 형성합니다.
따라서 속도가 공식적인 인터페이스 정의 (이 경우에는 해당되지 않음)의 일부가 아닌 한 이러한 메서드를 호출하는 것이 더 빠른지 묻는 것은 일반적으로 올바르지 않습니다.
전통적으로 이러한 종류의 바로 가기 (검색 및 검색 결합)는 언어, 인프라, OS, 플랫폼 또는 기계 아키텍처에 관계없이 더 효율적입니다. 또한 코드 구조에서 의도를 암시하지 않고 명시 적으로 의도를 표현하기 때문에 더 읽기 쉽습니다.
따라서 어리석은 낡은 핵에서 나온 대답은 ‘예’입니다 (TryGetValue는 Dictionary에서 값을 검색하기 위해 ContainsKey와 Item [Get]의 조합보다 선호됩니다).
이것이 이상하다고 생각되면 다음과 같이 생각하십시오. TryGetValue, ContainsKey 및 Item [Get]의 현재 구현에서 속도 차이가 발생하지 않더라도 향후 구현 (예 : .NET v5) 일 가능성이 있다고 가정 할 수 있습니다. 할 것입니다 (TryGetValue가 빠를 것입니다). 소프트웨어 수명에 대해 생각하십시오.
게다가, 전형적인 최신 인터페이스 정의 기술은 여전히 공식적으로 타이밍 제약을 정의하는 수단을 거의 제공하지 않는다는 점에 주목하는 것이 흥미 롭습니다. .NET v5일까요?
답변
빠른 테스트 프로그램을 만들면 사전에 1 백만 개의 항목이있는 TryGetValue를 사용하여 개선 된 결과가 있습니다.
결과 :
ContainsKey + 1000000 조회수 : 45ms
1000000 조회에 대한 TryGetValue : 26ms
테스트 앱은 다음과 같습니다.
static void Main(string[] args)
{
const int size = 1000000;
var dict = new Dictionary<int, string>();
for (int i = 0; i < size; i++)
{
dict.Add(i, i.ToString());
}
var sw = new Stopwatch();
string result;
sw.Start();
for (int i = 0; i < size; i++)
{
if (dict.ContainsKey(i))
result = dict[i];
}
sw.Stop();
Console.WriteLine("ContainsKey + Item for {0} hits: {1}ms", size, sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
for (int i = 0; i < size; i++)
{
dict.TryGetValue(i, out result);
}
sw.Stop();
Console.WriteLine("TryGetValue for {0} hits: {1}ms", size, sw.ElapsedMilliseconds);
}