簡體   English   中英

字符串的集合到字典

[英]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的回復

如果這確實是功課,並且你應該編寫自己的實現,那就不應該太難了。 這里只是一些提示,指出你正確的方向:

  1. Dictionary<TKey, TValue>有一個ContainsKey方法。
  2. 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM