2011-12-10 68 views
7

Tôi có một từ điển có giá trị gấp đôi và chuỗi làm khóa.Cách tính số lần xuất hiện của các giá trị duy nhất trong Từ điển?

Tôi muốn đếm số lần xuất hiện của từng giá trị trong Từ điển này và tôi muốn biết giá trị này (ví dụ: được lặp lại).

ví dụ:

key1, 2 
key2, 2 
key3, 3 
key4, 2 
key5, 5 
key6, 5 

Tôi muốn có được một danh sách:

2 - 3 (times) 
3 - 1 (once) 
5 - 2 (twice) 

Làm thế nào tôi có thể làm điều đó?

+1

Một chút biết thêm: Bạn có yêu cầu đếm các giá trị không lặp lại? Bạn có thể cho chúng tôi một ví dụ về dữ liệu và đầu ra mong muốn của bạn không? – Alan

+5

Thử nghiệm tăng gấp đôi cho bình đẳng là một thực tế rất có vấn đề. Bạn có thể muốn tránh đề cập đến nó nếu bạn muốn có câu trả lời. Việc sử dụng tính năng khác biệt của Linq(). Count() trên thuộc tính Giá trị là một cách tiếp cận phù hợp với thẻ của bạn. –

+2

Và làm thế nào để bạn muốn kiểm tra sự bình đẳng của đôi ở đây? –

Trả lời

9

Điều đầu tiên cần lưu ý là bạn không thực sự quan tâm đến các phím của từ điển. Bước một do đó là bỏ qua chúng như là không liên quan đến nhiệm vụ trong tay. Chúng tôi sẽ làm việc với thuộc tính Values của từ điển và tác phẩm giống với bất kỳ tập hợp số nguyên nào khác (hoặc thực sự là bất kỳ loại số nào khác mà chúng tôi có thể so sánh cho bình đẳng).

Có hai cách tiếp cận phổ biến cho vấn đề này, cả hai đều đáng được biết đến.

Đầu tiên sử dụng từ điển khác để giữ số lượng các giá trị:

//Start with setting up the dictionary you described. 
Dictionary<string, int> dict = new Dictionary<string, int>{ 
    {"key1", 2}, 
    {"key2", 2}, 
    {"key3", 3}, 
    {"key4", 2}, 
    {"key5", 5}, 
    {"key6", 5} 
}; 
//Create a different dictionary to store the counts. 
Dictionary<int, int> valCount = new Dictionary<int, int>(); 
//Iterate through the values, setting count to 1 or incrementing current count. 
foreach(int i in dict.Values) 
    if(valCount.ContainsKey(i)) 
     valCount[i]++; 
    else 
     valCount[i] = 1; 
//Finally some code to output this and prove it worked: 
foreach(KeyValuePair<int, int> kvp in valCount)//note - not sorted, that must be added if needed 
    Console.WriteLine("{0} - {1}", kvp.Key, kvp.Value); 

Hy vọng rằng điều này là khá đơn giản. Một cách khác là phức tạp hơn nhưng có một số ưu điểm:

//Start with setting up the dictionary you described. 
Dictionary<string, int> dict = new Dictionary<string, int>{ 
    {"key1", 2}, 
    {"key2", 2}, 
    {"key3", 3}, 
    {"key4", 2}, 
    {"key5", 5}, 
    {"key6", 5} 
}; 
IEnumerable<IGrouping<int, int>> grp = dict.Values.GroupBy(x => x); 
//Two options now. One is to use the results directly such as with the 
//equivalent code to output this and prove it worked: 
foreach(IGrouping<int, int> item in grp)//note - not sorted, that must be added if needed 
    Console.WriteLine("{0} - {1}", item.Key, item.Count()); 
//Alternatively, we can put these results into another collection for later use: 
Dictionary<int, int> valCount = grp.ToDictionary(g => g.Key, g => g.Count()); 
//Finally some code to output this and prove it worked: 
foreach(KeyValuePair<int, int> kvp in valCount)//note - not sorted, that must be added if needed 
    Console.WriteLine("{0} - {1}", kvp.Key, kvp.Value); 

(Có lẽ chúng ta muốn sử dụng var chứ không phải là tiết IEnumerable<IGrouping<int, int>>, nhưng nó có giá trị là chính xác khi giải thích code).

So sánh trực tiếp, phiên bản này kém hơn - cả phức tạp hơn để hiểu và kém hiệu quả hơn. Tuy nhiên, việc học cách tiếp cận này cho phép một số biến thể ngắn gọn và hiệu quả của cùng một kỹ thuật, vì vậy nó đáng xem xét.

GroupBy() có một điều tra và tạo một liệt kê khác chứa cặp khóa-giá trị trong đó giá trị là một liệt kê quá. Các lambda x => x có nghĩa là những gì nó được nhóm lại là chính nó, nhưng chúng tôi đã flexibilty cho các quy tắc nhóm khác nhau hơn thế. Nội dung của grp trông hơi giống:

{ 
    {Key=2, {2, 2, 2}} 
    {Key=3, {3}} 
    {Key=5, {5, 5}} 
} 

Vì vậy, nếu chúng ta lặp qua một này đối với từng nhóm chúng tôi kéo ra Key và gọi Count() vào nhóm, chúng tôi nhận được kết quả chúng ta muốn.

Bây giờ, trong trường hợp đầu tiên chúng tôi tích lũy số của chúng tôi trong một lần truyền O (n) duy nhất, trong khi ở đây chúng ta xây dựng nhóm trong thẻ O (n), và sau đó lấy số đếm trong một O thứ hai (n) vượt qua, làm cho nó kém hiệu quả hơn nhiều. Nó cũng khó hiểu hơn một chút, vậy tại sao phải nhắc đến nó?

Vâng, đầu tiên là một khi chúng ta làm hiểu nó, chúng ta có thể biến dòng:

IEnumerable<IGrouping<int, int>> grp = dict.Values.GroupBy(x => x); 
foreach(IGrouping<int, int> item in grp) 
    Console.WriteLine("{0} - {1}", item.Key, item.Count()); 

Into:

foreach(var item in dict.Values.GroupBy(x => x)) 
    Console.WriteLine("{0} - {1}", item.Key, item.Count()); 

Đó là khá súc tích, và trở thành thành ngữ.Nó đặc biệt tốt đẹp nếu chúng ta muốn tiếp tục và làm một cái gì đó phức tạp hơn với các cặp giá trị-đếm khi chúng ta có thể chuỗi này vào một hoạt động khác.

Phiên bản mà đặt kết quả vào một cuốn từ điển có thể còn ngắn gọn hơn vẫn:

var valCount = dict.Values.GroupBy(x => x).ToDictionary(g => g.Key, g => g.Count()); 

Ở đó, toàn bộ câu hỏi của bạn đã trả lời trong một dòng ngắn, chứ không phải là 6 (cắt ra bình luận) cho người đầu tiên phiên bản.

(Một số có thể thích thay thế dict.Values.GroupBy(x => x) bằng dict.GroupBy(x => x.Value) sẽ có cùng kết quả chính xác khi chúng tôi chạy Count() trên đó. Nếu bạn không chắc chắn lý do tại sao, hãy thử giải quyết).

Ưu điểm khác, là chúng tôi linh hoạt hơn với GroupBy trong các trường hợp khác. Vì những lý do này, những người đã quen sử dụng GroupBy có khả năng bắt đầu bằng vạch một dòng dict.Values.GroupBy(x => x).ToDictinary(g => g.Key, g => g.Count()); và sau đó thay đổi thành dạng dài hơn nhưng hiệu quả hơn của phiên bản đầu tiên (nơi chúng tôi tăng tổng số chạy trong từ điển mới) nếu nó đã chứng tỏ điểm phát sóng hiệu suất.

-1

Thậm chí đơn giản sẽ là:

Private Function CountOccurenceOfValue(dictionary As Dictionary(Of Integer, Integer), valueToFind As Integer) As Integer 
    Return (From temp In dictionary Where temp.Value.Equals(valueToFind) Select temp).Count() 
End Function 

(Có nó trong VB.NET, nhưng bạn không nên có nhiều rắc rối để chuyển sang C# :-))

+0

Người dùng yêu cầu C# và do đó câu trả lời sẽ được trình bày trong C#. – Neeko

Các vấn đề liên quan