【问题标题】:Which method of adding items to the ASP.NET Dictionary class is more efficient?向 ASP.NET Dictionary 类添加项的哪种方法更有效?
【发布时间】:2012-04-21 11:28:34
【问题描述】:

我在 ASP.NET 中使用 C# 将逗号分隔的字符串列表转换为字典(通过省略任何重复项):

string str = "1,2, 4, 2, 4, item 3,item2, item 3"; //Just a random string for the sake of this example

我想知道哪种方法更有效?

1 - 使用 try/catch 块:

Dictionary<string, string> dic = new Dictionary<string, string>();

string[] strs = str.Split(',');
foreach (string s in strs)
{
    if (!string.IsNullOrWhiteSpace(s))
    {
        try
        {
            string s2 = s.Trim();
            dic.Add(s2, s2);
        }
        catch
        {
        }
    }
}

2 - 或者使用 ContainsKey() 方法:

string[] strs = str.Split(',');
foreach (string s in strs)
{
    if (!string.IsNullOrWhiteSpace(s))
    {
        string s2 = s.Trim();
        if (!dic.ContainsKey(s2))
            dic.Add(s2, s2);
    }
}

编辑。感谢所有参与的人!

一个非常有趣的发现。如果你看下面dtb提供的答案,他提出了两种使用hashSet的方法。我会在这里配音:

方法一:

var hashSet = new HashSet<string>(from s in str.Split(',')
                           where !string.IsNullOrWhiteSpace(s)
                           select s.Trim()); 

方法二:

var hashSet = new HashSet<string>();
foreach (string s in str.Split(','))
{
     if (!string.IsNullOrWhiteSpace(s))
     {
         hashSet.Add(s.Trim());
     }
}

我问他哪种方法在性能方面更快,有趣的是,方法 2 更快。这是使用 Stopwatch 类完成的计时,方法是在一个循环中运行 Release 版本中的每个方法 1,000,000 次:

Method 1: 1,440 ms average
Method 2: 1,124 ms average

【问题讨论】:

    标签: c# asp.net performance dictionary


    【解决方案1】:

    如果您需要集合而不是字典,我建议您使用HashSet<T> Class

    HashSet

    表示一组值。

    集合是不包含重复元素且其元素没有特定顺序的集合。


    var hashSet = new HashSet<string>(from s in str.Split(',')
                                      where !string.IsNullOrWhiteSpace(s)
                                      select s.Trim());
    

    或同等

    var hashSet = new HashSet<string>();
    foreach (string s in str.Split(','))
    {
        if (!string.IsNullOrWhiteSpace(s))
        {
            hashSet.Add(s.Trim());
        }
    }
    

    【讨论】:

    • 谢谢,这似乎是一个正确的答案。我还学到了一些关于 HashSet 的知识。不过,我对您在 HashSet() 部分中添加的内容并不十分熟悉。是不是比我写出来更有效率?
    • @ahmd0:是的,它在字数和可读性方面效率更高,但在性能方面则不然。
    • @Tim Schmelter:谢谢。性能将是我的第一要务。那么在考虑性能的情况下,您将如何编写这个?
    • 使用分析器找出答案。我想这两个版本之间没有太大区别。如果你不熟悉 LINQ,我会选择第二个版本。
    • 只需使用Stopwatch Class 并比较两个版本所用的时间。测量时执行这两个版本数千次,编译 Release 并在没有调试器的情况下运行以获得有意义的结果。
    【解决方案2】:

    看起来你不需要字典:一个简单的 LINQ 表达式应该会给你一个没有重复项的列表:

    var res = str
        .Split(',')
        .Where(s => !string.IsNullOrWhitespace(s))
        .Select(s => s.Trim())
        .Distinct()
        .ToList();
    

    如果你坚持要有字典,你可以改用ToDictionary

    var res = str
        .Split(',')
        .Where(s => !string.IsNullOrWhitespace(s))
        .Select(s => s.Trim())
        .Distinct()
        .ToDictionary(s=>s, s=>s);
    

    强烈建议不要在正常的程序流程中使用try/catch,因为它隐藏了您的意图:C# 中的异常是为异常情况保留的,而不是您可以安全地用if / then / else 条件捕获的常规事物。

    【讨论】:

    • 感谢您告诉我,尽管您的方法没有像我展示的那样修剪值。
    • @ahmd0 这是一个相对简单的修复 - 请参阅编辑。一般来说,LINQ 在决定从初始集合中过滤掉什么方面提供了很大的灵活性。
    • 谢谢。只是好奇,在我的情况下 List 或 HashSet 哪个更好?我说的只是性能方面的。
    • @ahmd0 这完全取决于你以后打算用它做什么。如果您需要枚举一次,例如在一个循环中,忘记它,你可以在最后删除ToList;如果您需要一遍又一遍地迭代 entire 集合,那么List 更好;如果您需要反复检查特定项目的存在与否,HashSet 会胜出。所以这一切都取决于您的需求。
    • 哦,我明白了。感谢您的解释。
    【解决方案3】:

    使用.ContainsKey 的方法2 更语义,并且很可能比抑制异常更有效。

    【讨论】:

      【解决方案4】:

      使用异常来控制预期的执行流程通常是不受欢迎的,而且捕获异常的成本很高,所以我会选择 v2。如果它对你来说真的很重要,为什么不建立一个基准呢?我猜 2 是“更有效”,但你可以很容易地确认这一点。

      【讨论】:

        【解决方案5】:

        如果您没有使用字典中的值,您可以使用 HashSet&lt;string&gt; 代替,将项目添加到哈希集中会自动删除重复项:

        HashSet<string> set = new HashSet<string>(
          str.Split(',')
          .Select(s => s.Trim())
          .Where(s => s.Length > 0)
        );
        

        【讨论】:

        • @ahmd0:是的,他在我发布答案的同时添加了一个示例。
        猜你喜欢
        • 1970-01-01
        • 2013-08-02
        • 2012-10-01
        • 1970-01-01
        • 2013-06-05
        • 2010-10-23
        • 1970-01-01
        • 2019-11-22
        • 2011-12-12
        相关资源
        最近更新 更多