사전에 추가하는 다양한 방법


107

Dictionary.add(key, value)과 의 차이점은 무엇입니까 Dictionary[key] = value?

ArgumentException중복 키를 삽입 할 때 마지막 버전이 던지지 않는다는 것을 알았는데 첫 번째 버전을 선호하는 이유가 있습니까?

편집 : 누구든지 이것에 대한 정보의 권위있는 출처를 가지고 있습니까? 나는 MSDN을 시도했지만 항상 야생 거위 추적입니다 :(

답변:


109

성능은 거의 100 % 동일합니다. Reflector.net에서 클래스를 열어 확인할 수 있습니다.

This 인덱서입니다.

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

그리고 이것은 Add 메서드입니다.

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

다소 길기 때문에 전체 Insert 메서드를 게시하지는 않지만 메서드 선언은 다음과 같습니다.

private void Insert(TKey key, TValue value, bool add)

함수에서 더 아래로 내려 가면 다음과 같은 일이 발생합니다.

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

키가 이미 존재하는지 확인하고 존재하고 매개 변수 add가 true이면 예외를 발생시킵니다.

따라서 모든 목적과 의도에 대해 성능은 동일합니다.

다른 몇 가지 언급과 마찬가지로 동일한 키를 두 번 추가하려는 시도에 대해 확인이 필요한지 여부에 관한 것입니다.

긴 게시물에 대해 죄송합니다. 괜찮기를 바랍니다.


+1 매우 흥미 롭습니다. 게시물 주셔서 감사합니다! 다른 포스터가 암시
했듯이

70

첫 번째 버전은 새 KeyValuePair를 사전에 추가하여 키가 이미 사전에 있으면 던집니다. 두 번째는 인덱서를 사용하여 키가없는 경우 새 쌍을 추가하지만 사전에 이미있는 경우 키 값을 덮어 씁니다.

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

+1 위 정보에 대한 출처가 있습니까? 첫 번째 또는 후자의 형식을 사용하는 데 부작용이나 경고가 있는지 배우고 싶습니다.
Sune Rievers

3
내 머리 꼭대기에서 그런 소스가 실제로는 없지만 다른 의견에서 언급 한 것보다 더 많은 것이 있다고 생각하지 않습니다. 내가 올바르게 기억하는 경우 Add는 단순히 인덱서를 사용하지만 먼저 키가 이미 사용 중인지 확인합니다.
hhravn 2009

1
그의 문서가 최고 수준이기 때문에 Steffen에 대한 수락 된 답변을 변경했습니다. 그래도 이것은 여전히 ​​좋은 대답입니다.
Sune Rievers 2009

@Sune : 나쁜 움직임 ... 개인적으로이 대답은 Steffen보다 앞선 거리라고 생각합니다 ... 바로 요점과 적절한 예입니다.
demoncodemonkey

1
@SuneRievers 내 생각에 현재 받아 들여지는 답변 대신 이에 대한 답변을 받아 들이면 사람들에게 더 많은 도움이 될 것입니다. 이것은 (성능에 대해 이야기하고이 주제를 검색하는 거의 99 %의 사용자 (나와 같은)에 대해 말하는 것보다)가 아니라 ( "차이가 무엇인지"라는 질문에 정확히 답하기 때문에 "차이"가 필요했습니다. 주제), 허용 된 대답은 저와 폐기물 우리의 초 쓸모가 없었습니다 대신,이 답변이 정확합니다..
T.Todua

30

Dictionary.Add(key, value)Dictionary[key] = value다른 목적을 가지고 :

  • Add메서드를 사용하여 새 키 / 값 쌍 을 추가 하면 기존 키가 대체되지 않습니다 ( ArgumentException가 발생 함).
  • 키가 사전에 이미 있는지 여부를 신경 쓰지 않는 경우 인덱서를 사용합니다. 즉, 키가 사전에 없으면 키 / 값 쌍을 추가하고 키가 이미 있으면 지정된 키의 값을 바꿉니다. 사전에.

1
의도를 직접 설명하는 코드는 중요하고 매우 가치가 있습니다 (주석이 거의 필요하지 않음). 이 답변은 두 방법의 의도의 차이를 보여 주므로 하나를 선택할 때 따라야합니다. 즉, 항상 추가하거나 항상 추가 해야 한다는 것을 미리 알고있는 경우 '인덱서 추가'를 사용하지 마십시오 . IndexOutOfBounds 예외가 발생하면 예상치 못한 동작보다 낫습니다.
ryancdotnet

28

먼저 질문에 답하려면 사전의 목적과 기본 기술을 살펴 봐야합니다.

DictionaryKeyValuePair<Tkey, Tvalue>각 값이 고유 키로 표시되는 목록입니다 . 좋아하는 음식 목록이 있다고 가정 해 보겠습니다. 각 값 (음식 이름)은 고유 한 키 (위치 =이 음식을 얼마나 좋아하는지)로 표시됩니다.

예제 코드 :

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

건강을 유지하고 마음이 바뀌었고 좋아하는 "버거"를 샐러드로 바꾸고 싶다고 가정 해 보겠습니다. 목록은 여전히 ​​즐겨 찾기 목록이며 목록의 특성은 변경되지 않습니다. 당신이 가장 좋아하는 것은 목록에서 1 위를 유지하고 그 가치 만이 변할 것입니다. 이것은 당신이 이것을 부를 때입니다 :

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

하지만 당신이 프로그래머라는 사실을 잊지 마세요. 이제부터 당신의 문장은; 이모티콘은 컴파일 오류가 발생하고 모든 즐겨 찾기 목록이 0 인덱스 기반이기 때문에 사용을 거부합니다.

식단도 바뀌 었습니다! 따라서 목록을 다시 변경합니다.

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

정의에는 두 가지 가능성이 있습니다. 이전에 존재하지 않았던 것에 대한 새로운 정의를 제공하거나 이미 존재하는 정의를 변경하려는 것입니다.

Add 메서드를 사용하면 레코드를 추가 할 수 있지만 한 가지 조건에서만이 정의에 대한 키가 사전에 없을 수 있습니다.

이제 우리는 내부를 살펴볼 것입니다. 사전을 만들 때 컴파일러는 버킷을 예약합니다 (레코드를 저장할 메모리 공간). 버킷은 사용자가 정의하는 방식으로 키를 저장하지 않습니다. 각 키는 버킷 (Microsoft에서 정의)으로 이동하기 전에 해시되며 값 부분은 변경되지 않습니다.

예제를 단순화하기 위해 CRC32 해싱 알고리즘을 사용하겠습니다. 정의 할 때 :

myDietFavorites[0] = "Pizza";

버킷으로 이동하는 것은 db2dc565 "Pizza"(간체)입니다.

다음을 사용하여 값을 변경할 때 :

myDietFavorites[0] = "Spaghetti";

다시 db2dc565 인 0을 해시합니다. 한 다음 버킷에서이 값을 찾아 거기에 있는지 확인합니다. 거기에 있다면 키에 할당 된 값을 다시 작성하면됩니다. 그것이 없으면 버킷에 값을 넣을 것입니다.

다음과 같이 사전에서 Add 함수를 호출 할 때 :

myDietFavorite.Add(0, "Chocolate");

0을 해시하여 값을 버킷의 값과 비교합니다. 버킷이 없는 경우에만 버킷에 넣을 수 있습니다 .

특히 문자열 사전이나 문자 유형의 키로 작업하는 경우 작동 방식을 아는 것이 중요합니다. 해싱이 진행되기 때문에 대소 문자를 구분합니다. 예를 들어 "name"! = "Name". 이것을 묘사하기 위해 우리의 CRC32를 사용합시다.

"이름" 값 : e04112b1 "이름"값 : 1107fb5b


이 두 줄은 이해하기에 충분합니다 ....... 정의에는 두 가지 가능성이 있습니다. 이전에 존재하지 않았던 것에 대해 새로운 정의를 제공하거나 이미 존재하는 정의를 변경하려는 것입니다. Add 메서드를 사용하면 레코드를 추가 할 수 있지만 한 가지 조건에서만이 정의에 대한 키가 사전에 없을 수 있습니다.
Niraj Trivedi

4

예, 이것이 차이점입니다. 키가 이미 존재하는 경우 Add 메서드는 예외를 throw합니다.

Add 메서드를 사용하는 이유는 바로 이것입니다. 사전에 이미 키가 포함되어 있지 않은 경우 일반적으로 문제를 인식 할 수 있도록 예외를 원합니다.


0

성능면에서 가능한 유사점보다 더 정확하고 가독성이 높은 코드를 사용하십시오.

나는 추가를 설명하는 작업을 느낍니다. 키의 존재는 이미 정말 드문 예외이므로 추가로 가장 잘 표현됩니다. 의미 론적으로 더 의미가 있습니다.

dict[key] = value더 나은 대체를 나타냅니다. 이 코드가 보이면 어쨌든 키가 이미 사전에있을 것으로 예상합니다.


키가 먼저 존재하는지 확인하지 않으면 약간의 성능 향상이 있다고 가정합니다. 나는 기대하지 않을 dic[key] = value키가 이미 존재했다, 그러나 나는 이제 논쟁의 여지가 추측)
Sune Rievers에게

2
+ 키가 이미 표시되었는지 확인하는 방법으로 던지기를 사용해서는 안된다고 생각합니다. if (! strings.ContainsKey ( "foo")) strings.Add ( "foo", "bar");
hhravn 2009

0

하나는 값을 할당하고 다른 하나는 새 키와 값을 사전에 추가하는 것입니다.


0

사전에 값을 삽입하려면

 Dictionary<string, string> dDS1 = new Dictionary<string, string>();//Declaration
 dDS1.Add("VEqpt", "aaaa");//adding key and value into the dictionary
 string Count = dDS1["VEqpt"];//assigning the value of dictionary key to Count variable
 dDS1["VEqpt"] = Count + "bbbb";//assigning the value to key
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.