代码之家  ›  专栏  ›  技术社区  ›  Michael Goldshteyn

字典字符串集合

  •  2
  • Michael Goldshteyn  · 技术社区  · 14 年前

    var strings = new string[] { "abc", "def", "def", "ghi", "ghi", "ghi", "klm" };
    

    使用LINQ创建一个字符串字典,该字典包含集合中该字符串的出现次数:

    IDictionary<string,int> stringToNumOccurrences = ...;
    

    6 回复  |  直到 14 年前
        1
  •  8
  •   Darin Dimitrov    14 年前
    var dico = strings.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
    
        2
  •  5
  •   Jon Skeet    14 年前

    Timwi/Darin的建议将在一次传递原始集合的过程中执行此操作,但是 blog post 更多关于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 current 从空开始的值。。。但这最终在其他几个方面变得很恶心。(我试过了:)当我需要对第一个值进行特殊的案例处理时,我通常使用上面的模式。

    实际上你 能够 使用LINQ执行此操作 Aggregate ,但那会很糟糕。

        3
  •  3
  •   Timwi    14 年前

    stringToNumOccurrences = strings.GroupBy(s => s)
                                    .ToDictionary(g => g.Key, g => g.Count());
    
        4
  •  0
  •   Community Neeleshkumar S    7 年前

    如果这是实际的生产代码,我会 Timwi's response .

    1. Dictionary<TKey, TValue> 有一个 ContainsKey 方法。
    2. IDictionary<TKey, TValue> 接口的 this[TKey] 属性是可设置的;即,您可以 dictionary[key] = 1 (也就是说你也可以 dictionary[key] += 1

    根据这些线索,我认为你应该能够找出如何做到“手”

        5
  •  0
  •   Timwi    14 年前

    如果你想找一个 有效率的 (快速)解决方案,然后 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;
    
        6
  •  0
  •   corvuscorax    14 年前

    这是一个 foreach公司

    我必须承认,我觉得它比乔恩的版本简单,看不出有什么不好。乔恩?有人吗?

    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的简单:-)