Câu hỏi Cách tốt nhất để lặp qua một từ điển là gì?


Tôi đã nhìn thấy một vài cách khác nhau để lặp qua một từ điển trong C #. Có cách nào tiêu chuẩn không?


1949
2017-09-26 18:20


gốc


Tôi ngạc nhiên có rất nhiều câu trả lời cho câu hỏi này, cùng với một câu trả lời là 923 lần .. (tôi sử dụng forcourse) .. Tôi cho rằng, hoặc ít nhất là nếu bạn phải lặp lại từ điển, rất có thể bạn Tôi đã phải đưa ra nhận xét này, bởi vì tôi đã thấy từ điển bị lạm dụng theo những cách mà IMHO không thích hợp ... Có thể có những trường hợp hiếm hoi khi bạn lặp lại từ điển, thay vì tra cứu, đó là những gì nó được thiết kế cho .. Hãy nhớ rằng, trước khi tự hỏi làm thế nào để lặp qua một từ điển. - Vikas Gupta
@VikasGupta Bạn sẽ gợi ý làm gì với bộ sưu tập các cặp khóa-giá trị khi bạn không biết khóa sẽ là gì? - nasch
@nasch: myDictionary.Keys sẽ cung cấp cho bạn một bộ sưu tập chứa các khóa myDictionary. - displayName
@displayName Nếu bạn muốn làm điều gì đó với mỗi cặp khóa-giá trị nhưng không có tham chiếu đến các khóa để sử dụng để tra cứu các giá trị, bạn sẽ lặp lại từ điển, đúng không? Tôi đã chỉ ra rằng có thể có lần bạn muốn làm điều đó, mặc dù tuyên bố của Vikas rằng đây thường là sử dụng không chính xác. - nasch
Để nói rằng việc sử dụng không chính xác ngụ ý rằng có một giải pháp thay thế tốt hơn. Phương án đó là gì? - Kyle Delaney


Các câu trả lời:


foreach(KeyValuePair<string, string> entry in myDictionary)
{
    // do something with entry.Value or entry.Key
}

2901
2017-09-26 18:22



Điều gì xảy ra nếu tôi không biết chính xác loại khóa / giá trị trong Từ điển. Sử dụng var entry tốt hơn trong trường hợp đó, và do đó tôi đã bỏ phiếu câu trả lời này trên một cái nhìn thứ hai thay vì một ở trên. - Ozair Kafray
@OzairKafray sử dụng var khi bạn không biết loại này thường là thực hành không tốt. - Nate
Câu trả lời này là cao hơn bởi vì Pablo đã không mặc định để sử dụng coder lười "var" làm obfuscates kiểu trả về. - MonkeyWrench
@MonkeyWrench: Meh. Visual Studio biết loại là gì; tất cả những gì bạn phải làm là di chuột qua biến để tìm hiểu. - Robert Harvey♦
Như tôi hiểu nó, var chỉ hoạt động nếu loại được biết tại thời gian biên dịch. Nếu Visual Studio biết loại thì nó có sẵn để bạn tìm ra. - Kyle Delaney


Nếu bạn đang cố gắng sử dụng một từ điển chung trong C # như bạn sẽ sử dụng một mảng kết hợp trong một ngôn ngữ khác:

foreach(var item in myDictionary)
{
  foo(item.Key);
  bar(item.Value);
}

Hoặc, nếu bạn chỉ cần lặp qua bộ sưu tập khóa, hãy sử dụng

foreach(var item in myDictionary.Keys)
{
  foo(item);
}

Và cuối cùng, nếu bạn chỉ quan tâm đến các giá trị:

foreach(var item in myDictionary.Values)
{
  foo(item);
}

(Hãy lưu ý rằng var từ khóa là một tính năng tùy chọn C # 3.0 trở lên, bạn cũng có thể sử dụng loại khóa / giá trị chính xác của mình tại đây)


646
2017-09-26 18:22



các tính năng var là cần thiết nhất cho khối mã đầu tiên của bạn :) - nawfal
Tôi đánh giá cao câu trả lời này chỉ ra rằng bạn có thể lặp qua các khóa hoặc các giá trị một cách rõ ràng. - Rotsiser Mho
Tôi không thích sử dụng var ở đây. Cho rằng nó chỉ là cú pháp đường, tại sao lại sử dụng nó ở đây? Khi ai đó đang cố gắng đọc mã, họ sẽ phải nhảy xung quanh mã để xác định loại myDictionary (trừ khi đó là tên thật của khóa học). Tôi nghĩ rằng việc sử dụng var là tốt khi loại hiển thị, ví dụ: var x = "some string" nhưng khi nó không phải là ngay lập tức rõ ràng tôi nghĩ rằng đó là lười biếng mã hóa mà đau người đọc mã / người đánh giá - James Wierzba
var nên được sử dụng một cách tiết kiệm, theo ý kiến ​​của tôi. Đặc biệt ở đây, nó không mang tính xây dựng: loại KeyValuePair có thể liên quan đến câu hỏi. - Sinjai


Trong một số trường hợp, bạn có thể cần một bộ đếm có thể được cung cấp bởi việc thực hiện vòng lặp. Đối với điều đó, LINQ cung cấp ElementAt cho phép những điều sau đây:

for (int index = 0; index < dictionary.Count; index++) {
  var item = dictionary.ElementAt(index);
  var itemKey = item.Key;
  var itemValue = item.Value;
}

107
2018-03-10 20:44



Để sử dụng phương thức '.ElementAt', hãy nhớ: using System.Linq; Điều này không được bao gồm trong fx. các lớp thử nghiệm được tạo tự động. - Tinia
Đây là cách để đi nếu bạn đang sửa đổi các giá trị liên kết với các phím. Nếu không thì một ngoại lệ sẽ được ném khi sửa đổi và sử dụng foreach (). - Mike de Klerk
Hãy cẩn thận khi sử dụng. Xem ở đây: stackoverflow.com/a/2254480/253938 - RenniePet
Không phải ElementAt một hoạt động O (n)? - Arturo Torres Sánchez
Câu trả lời này là hoàn toàn không xứng đáng với rất nhiều upvotes. Một từ điển không có thứ tự ngầm, vì vậy sử dụng .ElementAt trong bối cảnh này có thể dẫn đến lỗi tinh tế. Nghiêm trọng hơn là điểm của Arturo ở trên. Bạn sẽ lặp lại từ điển dictionary.Count + 1 lần dẫn đến độ phức tạp O (n ^ 2) cho một phép toán chỉ nên là O (n). Nếu bạn thực sự cần một chỉ mục (nếu bạn làm vậy, có thể bạn đang sử dụng sai loại bộ sưu tập ở nơi đầu tiên), bạn nên lặp lại dictionary.Select( (kvp, idx) => new {Index = idx, kvp.Key, kvp.Value}) thay vào đó và không sử dụng .ElementAt bên trong vòng lặp. - spender


Phụ thuộc vào việc bạn có đang theo chìa khóa hay các giá trị ...

Từ MSDN Dictionary(TKey, TValue) Mô tả lớp học:

// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
    Console.WriteLine("Key = {0}, Value = {1}", 
        kvp.Key, kvp.Value);
}

// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
    openWith.Values;

// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
    Console.WriteLine("Value = {0}", s);
}

// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
    openWith.Keys;

// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
    Console.WriteLine("Key = {0}", s);
}

75
2017-09-26 18:27





Nói chung, yêu cầu "cách tốt nhất" không có ngữ cảnh cụ thể giống như yêu cầu màu sắc tốt nhất là gì.

Một mặt, có nhiều màu sắc và không có màu sắc tốt nhất. Nó phụ thuộc vào nhu cầu và thường về hương vị, quá.

Mặt khác, có nhiều cách để lặp qua một từ điển trong C # và không có cách nào tốt nhất. Nó phụ thuộc vào nhu cầu và thường về hương vị, quá.

Cách đơn giản nhất

foreach (var kvp in items)
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Nếu bạn chỉ cần giá trị (cho phép gọi nó là item, dễ đọc hơn kvp.Value).

foreach (var item in items.Values)
{
    doStuff(item)
}

Nếu bạn cần một thứ tự sắp xếp cụ thể

Nói chung, người mới bắt đầu ngạc nhiên về thứ tự liệt kê một từ điển.

LINQ cung cấp cú pháp ngắn gọn cho phép chỉ định thứ tự (và nhiều thứ khác), ví dụ:

foreach (var kvp in items.OrderBy(kvp => kvp.Key))
{
    // key is kvp.Key
    doStuff(kvp.Value)
}

Một lần nữa bạn chỉ có thể cần giá trị. LINQ cũng cung cấp một giải pháp ngắn gọn để:

  • lặp lại trực tiếp trên giá trị (cho phép gọi nó item, dễ đọc hơn kvp.Value)
  • nhưng được sắp xếp theo các phím

Đây là:

foreach (var item in items.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Value))
{
    doStuff(item)
}

Có nhiều trường hợp sử dụng thực tế hơn mà bạn có thể làm từ những ví dụ này. Nếu bạn không cần một thứ tự cụ thể, chỉ cần dính vào "cách đơn giản nhất" (xem ở trên)!


55
2017-08-10 11:15



Người cuối cùng nên là .Values và không phải là một mệnh đề lựa chọn. - Mafii
@Mafii Bạn có chắc chắn? Các giá trị được OrderBy trả về không thuộc loại KeyValuePair, chúng không có Value cánh đồng. Loại chính xác tôi thấy ở đây là IOrderedEnumerable<KeyValuePair<TKey, TValue>>. Có lẽ bạn có ý nghĩa gì khác? Bạn có thể viết một dòng hoàn chỉnh cho thấy những gì bạn có nghĩa là (và thử nghiệm nó)? - Stéphane Gourichon
Tôi nghĩ câu trả lời này chứa những gì tôi muốn nói: stackoverflow.com/a/141105/5962841 nhưng sửa tôi nếu tôi nhầm lẫn - Mafii
@Mafii Đọc lại toàn bộ câu trả lời của tôi, giải thích giữa các phần mã cho biết ngữ cảnh. Câu trả lời bạn đề cập đến giống như phần mã thứ hai trong câu trả lời của tôi (không yêu cầu thứ tự). Ở đó tôi vừa viết items.Value như bạn đã đề xuất. Trong trường hợp của phần thứ tư mà bạn đã nhận xét, Select() là một cách để gây ra foreach liệt kê trực tiếp các giá trị trong từ điển thay vì các cặp khóa-giá trị. Nếu bằng cách nào đó bạn không thích Select() trong trường hợp này, bạn có thể thích phần mã thứ ba. Điểm của phần thứ tư là để cho thấy rằng người ta có thể xử lý trước bộ sưu tập với LINQ. - Stéphane Gourichon
Nếu bạn làm .Keys.Orderby() bạn sẽ lặp lại trên danh sách các phím. Nếu đó là tất cả những gì bạn cần, tốt. Nếu bạn cần giá trị, thì trong vòng lặp, bạn phải truy vấn từ điển trên mỗi khóa để lấy giá trị. Trong nhiều kịch bản, nó sẽ không tạo ra sự khác biệt thực tế. Trong kịch bản hiệu suất cao, nó sẽ. Giống như tôi đã viết ở phần đầu của câu trả lời: "có rất nhiều cách (...) và không có cách nào tốt nhất. Nó phụ thuộc vào nhu cầu và thường về khẩu vị". - Stéphane Gourichon


Tôi sẽ nói foreach là cách tiêu chuẩn, mặc dù nó rõ ràng phụ thuộc vào những gì bạn đang tìm kiếm

foreach(var kvp in my_dictionary) {
  ...
}

Đó là những gì bạn đang tìm kiếm?


36
2017-09-26 18:22



Um, không đặt tên cho mục "giá trị" khá là khó hiểu? Bạn thường sẽ sử dụng cú pháp như "value.Key" và "value.Value", điều này không trực quan đối với bất kỳ ai khác, những người sẽ đọc mã, đặc biệt nếu họ không quen với cách .Net Dictionary được triển khai . - RenniePet
@RenniePet kvp thường được sử dụng để đặt tên cho các cá thể KeyValuePair khi lặp qua các từ điển và cấu trúc dữ liệu liên quan: foreach(var kvp in myDictionary){.... - mbx


Bạn cũng có thể thử điều này trên các bộ từ điển lớn để xử lý đa luồng.

dictionary
.AsParallel()
.ForAll(pair => 
{ 
    // Process pair.Key and pair.Value here
});

28
2018-06-11 13:32



@ WiiMaxx và quan trọng hơn nếu các mục này KHÔNG phụ thuộc vào nhau - Mafii