Các cách khác nhau để thêm vào Từ điển


107

Sự khác biệt trong Dictionary.add(key, value)Dictionary[key] = value?

Tôi nhận thấy rằng phiên bản cuối cùng không ném một ArgumentException khi chèn một khóa trùng lặp, nhưng có lý do gì để thích phiên bản đầu tiên không?

Chỉnh sửa : Có ai có nguồn thông tin có thẩm quyền về điều này không? Tôi đã thử MSDN, nhưng nó vẫn luôn là một cuộc rượt đuổi ngỗng trời :(

Câu trả lời:


109

Hiệu suất gần như giống nhau 100%. Bạn có thể kiểm tra điều này bằng cách mở lớp học trong Reflector.net

Đây là Chỉ mục này:

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);
    }
}

Và đây là phương thức Thêm:

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

Tôi sẽ không đăng toàn bộ phương thức Chèn vì nó khá dài, tuy nhiên, khai báo phương thức là:

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

Và sâu hơn trong hàm, điều này xảy ra:

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

Kiểm tra xem khóa đã tồn tại chưa và nếu có và tham số thêm vào là đúng, nó sẽ ném ngoại lệ.

Vì vậy, đối với tất cả các mục đích và ý định, hiệu suất là như nhau.

Giống như một số đề cập khác, tất cả là về việc bạn có cần kiểm tra hay không, để thử thêm cùng một khóa hai lần.

Xin lỗi vì bài viết dài dòng, tôi hy vọng nó không sao.


+1 Rất thú vị, cảm ơn vì bài đăng của bạn! Có vẻ như hiệu suất đó là gần như giống hệt nhau ở đây, như các áp phích khác đã gợi ý về, dù sao tìm tuyệt vời :)
Sune Rievers

70

Phiên bản đầu tiên sẽ thêm KeyValuePair mới vào từ điển, ném nếu khóa đã có trong từ điển. Cách thứ hai, sử dụng trình lập chỉ mục, sẽ thêm một cặp mới nếu khóa không tồn tại, nhưng ghi đè giá trị của khóa nếu nó đã tồn tại trong từ điển.

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 Bạn đã có nguồn cho thông tin trên chưa? Tôi muốn tìm hiểu xem có bất kỳ tác dụng phụ hoặc cảnh báo nào khi sử dụng hình thức đầu tiên hoặc hình thức sau hay không.
Sune Rievers

3
Không thực sự có một nguồn như vậy, chỉ là suy nghĩ của tôi, nhưng tôi không nghĩ rằng có nhiều điều về nó, hơn được đề cập trong các bình luận khác. Nếu tôi nhớ không nhầm thì Add chỉ sử dụng trình lập chỉ mục, nhưng trước tiên hãy kiểm tra xem Key đã được sử dụng chưa.
hhravn 03/12/09

1
Đã thay đổi câu trả lời được chấp nhận cho Steffen's, bởi vì tài liệu của anh ấy là hàng đầu. Đây vẫn là một câu trả lời tuyệt vời.
Sune Rievers

@Sune: Xấu xa ... cá nhân tôi nghĩ câu trả lời này đi trước Steffen ... thẳng vào vấn đề và là một ví dụ điển hình.
Devilcodemonkey

1
@SuneRievers Tôi nghĩ, nó sẽ hữu ích hơn cho mọi người, nếu câu trả lời được chấp nhận cho điều này, thay vì câu trả lời được chấp nhận hiện tại. Bởi vì điều này trả lời chính xác câu hỏi ("sự khác biệt là gì"), chứ không phải là câu được chấp nhận (nói về hiệu suất và gần như 99% người dùng tìm kiếm chủ đề này (như tôi), cần "sự khác biệt" (lý do tại sao tôi gặp điều này chủ đề), và câu trả lời được chấp nhận là vô ích đối với tôi và lãng phí thứ hai của chúng tôi. Thay vào đó, câu trả lời này là chính xác.
T.Todua

30

Dictionary.Add(key, value)Dictionary[key] = valuecó các mục đích khác nhau:

  • Sử dụng Addphương pháp để thêm cặp khóa / giá trị mới, các khóa hiện có sẽ không bị thay thế (an ArgumentExceptionđược ném).
  • Sử dụng trình lập chỉ mục nếu bạn không quan tâm liệu khóa đã tồn tại trong từ điển hay chưa, nói cách khác: thêm cặp khóa / giá trị nếu khóa không có trong từ điển hoặc thay thế giá trị cho khóa được chỉ định nếu khóa đã có trong từ điển.

1
Mã tự mô tả ý định là quan trọng và vô cùng có giá trị (và yêu cầu ít hoặc không cần nhận xét). Câu trả lời này cho thấy sự khác biệt về ý định với cả hai phương pháp và cần được tuân thủ khi chọn một phương pháp. Nói cách khác, không sử dụng 'chỉ mục thêm' khi bạn biết trước rằng bạn sẽ luôn thêm hoặc thậm chí luôn phải thêm. Có một ngoại lệ IndexOutOfBounds được ném ra sẽ tốt hơn hành vi không mong muốn.
ryancdotnet

28

Để trả lời câu hỏi trước tiên chúng ta cần xem xét mục đích của từ điển và công nghệ cơ bản.

Dictionary là danh sách của KeyValuePair<Tkey, Tvalue> mà mỗi giá trị được biểu diễn bằng khóa duy nhất của nó. Giả sử chúng tôi có một danh sách các loại thực phẩm yêu thích của bạn. Mỗi giá trị (tên món ăn) được thể hiện bằng khóa duy nhất của nó (vị trí = mức độ bạn thích món ăn này).

Mã ví dụ:

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

Giả sử bạn muốn giữ sức khỏe, bạn đã thay đổi quyết định và bạn muốn thay thế món "Burger" yêu thích của mình bằng món salad. Danh sách của bạn vẫn là danh sách yêu thích của bạn, bạn sẽ không thay đổi bản chất của danh sách. Yêu thích của bạn sẽ vẫn là số một trong danh sách, chỉ có điều giá trị của nó sẽ thay đổi. Đây là khi bạn gọi điều này:

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

Nhưng đừng quên bạn là lập trình viên, và từ bây giờ bạn hoàn thành các câu của mình với; bạn từ chối sử dụng biểu tượng cảm xúc vì chúng sẽ gây ra lỗi biên dịch và tất cả danh sách yêu thích đều dựa trên 0 chỉ mục.

Chế độ ăn uống của bạn cũng thay đổi! Vì vậy, bạn thay đổi danh sách của mình một lần nữa:

/*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");

Có hai khả năng với việc xác định, bạn muốn đưa ra một định nghĩa mới cho một thứ chưa tồn tại trước đó hoặc bạn muốn thay đổi định nghĩa đã tồn tại.

Phương thức Thêm cho phép bạn thêm bản ghi nhưng chỉ với một điều kiện: khóa cho định nghĩa này có thể không tồn tại trong từ điển của bạn.

Bây giờ chúng ta sẽ xem xét dưới mui xe. Khi bạn đang tạo từ điển, trình biên dịch của bạn đặt chỗ trước cho thùng (khoảng trống trong bộ nhớ để lưu các bản ghi của bạn). Nhóm không lưu trữ khóa theo cách bạn xác định chúng. Mỗi khóa được băm trước khi chuyển đến nhóm (do Microsoft định nghĩa), đáng nói là phần giá trị không thay đổi.

Tôi sẽ sử dụng thuật toán băm CRC32 để đơn giản hóa ví dụ của mình. Khi bạn xác định:

myDietFavorites[0] = "Pizza";

Những gì sẽ đến với thùng là db2dc565 "Pizza" (đơn giản hóa).

Khi bạn thay đổi giá trị bằng:

myDietFavorites[0] = "Spaghetti";

Bạn băm số 0 của mình lại là db2dc565 sau đó bạn tra cứu giá trị này trong nhóm của mình để tìm xem nó có ở đó không. Nếu nó ở đó, bạn chỉ cần viết lại giá trị được gán cho khóa. Nếu nó không ở đó, bạn sẽ đặt giá trị của mình vào nhóm.

Khi bạn gọi chức năng Thêm trên từ điển của mình như:

myDietFavorite.Add(0, "Chocolate");

Bạn băm số 0 của mình để so sánh giá trị của nó với giá trị trong nhóm. Bạn chỉ có thể đặt nó vào thùng nếu nó không ở đó .

Điều quan trọng là phải biết nó hoạt động như thế nào, đặc biệt nếu bạn làm việc với từ điển kiểu khóa chuỗi hoặc ký tự char. Nó phân biệt chữ hoa chữ thường vì trải qua quá trình băm. Vì vậy, ví dụ "name"! = "Name". Hãy sử dụng CRC32 của chúng tôi để mô tả điều này.

Giá trị cho "tên" là: e04112b1 Giá trị cho "Tên" là: 1107fb5b


Hai dòng này là đủ để hiểu ....... Có hai khả năng với việc định nghĩa, bạn muốn đưa ra một định nghĩa mới cho một thứ chưa tồn tại trước đó hoặc bạn muốn thay đổi định nghĩa đã tồn tại. Phương thức Thêm cho phép bạn thêm bản ghi nhưng chỉ với một điều kiện: khóa cho định nghĩa này có thể không tồn tại trong từ điển của bạn.
Niraj Trivedi

4

Vâng, đó là sự khác biệt, phương thức Add ném một ngoại lệ nếu khóa đã tồn tại.

Lý do để sử dụng phương thức Add chính là điều này. Nếu từ điển không được cho là đã chứa khóa, bạn thường muốn có ngoại lệ để được thông báo về vấn đề.


0

Với hầu hết các điểm tương đồng có thể xảy ra về hiệu suất, hãy sử dụng bất kỳ điều gì cảm thấy đúng hơn và dễ đọc hơn đối với đoạn mã bạn đang sử dụng.

Tôi cảm thấy một phép toán mô tả một phép bổ sung, vì sự hiện diện của khóa đã là một ngoại lệ thực sự hiếm hoi được thể hiện tốt nhất với phép bổ sung. Về mặt ngữ nghĩa, nó có ý nghĩa hơn.

Sự dict[key] = valuethay thế tốt hơn. Nếu tôi nhìn thấy mã đó, tôi nửa mong đợi khóa đã có trong từ điển.


Tôi cho rằng có một hiệu suất nhỏ đạt được từ việc không kiểm tra xem khóa có tồn tại trước hay không. Tôi sẽ không mong đợi từ dic[key] = valuerằng chìa khóa đã hiện diện, nhưng tôi đoán rằng nhân gây tranh cãi;)
Sune Rievers

2
+ Tôi nghĩ rằng ném không bao giờ được sử dụng như một cách để kiểm tra xem khóa đã được biểu diễn hay chưa. if (! string.ContainsKey ("foo")) string.Add ("foo", "bar");
hhravn

0

Một là gán một giá trị trong khi cái kia thêm vào Từ điển một Khóa và Giá trị mới.


0

Để chèn Giá trị vào Từ điển

 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.