[英]Collection of strings to dictionary
給定一個有序的字符串集合:
var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
使用LINQ創建字符串字典到集合中該字符串的出現次數:
IDictionary<string,int> stringToNumOccurrences = ...;
最好一次通過琴弦收集......
var dico = strings.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
Timwi /達林的建議將在單傳過來的原始集合執行此,但它將會為集團多個緩沖區。 LINQ並不是非常擅長這種計數,這樣的問題是我編寫Push LINQ的最初動機。 您可能希望閱讀我的博客文章 ,了解有關為什么LINQ在這里效率不高的詳細信息。
推LINQ和相同想法的更令人印象深刻的實現 - Reactive Extensions - 可以更有效地處理這個問題。
當然,如果你真的不太關心額外的效率,那就去GroupBy
:)
編輯:我沒有注意到你的琴弦是訂購的。 這意味着你可以更有效,因為你知道,一旦你看到串x,然后y字符串,如果X和Y是不同的,你永遠也不會再見到X。 LINQ中沒有任何內容可以讓這更容易,但你可以很容易地自己做:
public static IDictionary<string, int> CountEntries(IEnumerable<string> strings)
{
var dictionary = new Dictionary<string, int>();
using (var iterator = strings.GetEnumerator())
{
if (!iterator.MoveNext())
{
// No entries
return dictionary;
}
string current = iterator.Current;
int currentCount = 1;
while (iterator.MoveNext())
{
string next = iterator.Current;
if (next == current)
{
currentCount++;
}
else
{
dictionary[current] = currentCount;
current = next;
currentCount = 1;
}
}
// Write out the trailing result
dictionary[current] = currentCount;
}
return dictionary;
}
這是O(n),除了在寫入值時不涉及字典查找。 另一種實現方式是使用foreach
和一個從null開始的current
值...但最終在其他幾種方式上變得非常狡猾。 (我已經嘗試過了:)當我需要第一個值的特殊情況處理時,我通常會使用上面的模式。
實際上你可以使用Aggregate
使用LINQ來做到這一點,但它會非常討厭。
標准LINQ方式是這樣的:
stringToNumOccurrences = strings.GroupBy(s => s)
.ToDictionary(g => g.Key, g => g.Count());
如果這是實際的生產代碼,我會選擇Timwi的回復 。
如果這確實是功課,並且你應該編寫自己的實現,那就不應該太難了。 這里只是一些提示,指出你正確的方向:
Dictionary<TKey, TValue>
有一個ContainsKey
方法。 IDictionary<TKey, TValue>
接口的this[TKey]
屬性是可設置的; 即,你可以做dictionary[key] = 1
(這意味着你也可以做dictionary[key] += 1
)。 從這些線索中我認為你應該能夠“手工”地弄清楚如何做到這一點。
如果您正在尋找一種特別有效 (快速)的解決方案,那么GroupBy
對您來說可能太慢了。 你可以使用一個循環:
var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
var stringToNumOccurrences = new Dictionary<string, int>();
foreach (var str in strings)
{
if (stringToNumOccurrences.ContainsKey(str))
stringToNumOccurrences[str]++;
else
stringToNumOccurrences[str] = 1;
}
return stringToNumOccurrences;
這是一個foreach版本,就像Jon提到的那樣,他在答案中發現“非常狡猾”。 我把它放在這里,所以有一些具體可談的內容。
我必須承認,我發現它比Jon的版本更簡單,並且無法真正看到它的含義。 喬恩? 任何人?
static Dictionary<string, int> CountOrderedSequence(IEnumerable<string> source)
{
var result = new Dictionary<string, int>();
string prev = null;
int count = 0;
foreach (var s in source)
{
if (prev != s && count > 0)
{
result.Add(prev, count);
count = 0;
}
prev = s;
++count;
}
if (count > 0)
{
result.Add(prev, count);
}
return result;
}
更新為空源添加必要的檢查 - 我仍然認為它比Jon更簡單:-)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.