代码之家  ›  专栏  ›  技术社区  ›  willeM_ Van Onsem

C中字符串类型的最快(内置)比较是什么#

  •  32
  • willeM_ Van Onsem  · 技术社区  · 15 年前

    对于C中的字符串类型,最快的内置比较方法是什么?我不在乎排版/语义意义:目的是在排序列表中使用比较器,以便在大型集合中快速搜索。我认为只有两种方法: Compare CompareOrdinal . 最快的是什么?

    此外,是否有更快的字符串比较方法?

    8 回复  |  直到 7 年前
        1
  •  55
  •   Community CDub    8 年前

    我假设你想要一个小于/等于/大于比较,而不仅仅是平等;平等是一个稍微不同的话题,尽管原则基本上是相同的。如果你只是在寻找 存在 有点像 SortedList ,我会考虑使用 Dictionary<string, XXX> 相反-你真的需要所有的排序吗?

    String.CompareOrdinal 或使用超负荷 String.Compare 它允许提供比较,并指定顺序(区分大小写)比较,例如 String.Compare(x, y, StringComparison.Ordinal) 会是最快的。

    基本上是序数比较 只是 需要一个字符一个字符地遍历这两个字符串,直到找到差异为止。如果没有发现任何差异,并且长度相同,则结果为0。如果没有发现任何差异,但长度不同,则较长的字符串被视为“较大”。如果它 找到一个不同点,它可以立即计算出哪个字符被认为是“较大的”,根据哪个字符在序数术语中是“较大的”。

    换句话来说,这就像是在两个人之间做一个明显的比较 char[] 价值观。

    文化敏感的比较必须执行各种复杂的壮举,这取决于你所使用的精确文化。有关此示例,请参见 this question . 很明显,遵循更复杂的规则会使速度变慢。

        2
  •  11
  •   Max    11 年前

    我刚刚注意到,通过首先比较字符串长度(如果等于),然后使用string.compare方法,我自己的代码的性能提高了50%。所以在一个循环中,我有:

    VB:

    If strA.length = strB.length then
       if string.compare(strA,strB,true) = 0 then
          TheyAreEqual
       End if
    End if
    

    C:

    if(strA.Length == strB.Length)
    {
       if(string.Compare(strA,strB,true) == 0)
       {
           //they are equal
       }
    }
    

    这可能取决于你自己的条件,但它似乎对我很有效。

        3
  •  4
  •   Sam Harwell    15 年前

    最快的是带引用相等测试的内部字符串,但是您只需要进行相等测试,而且它的内存开销非常大——非常昂贵,以至于 这几乎不是推荐的课程 .

    除此之外,区分大小写的序数测试将是最快的,并且绝对推荐此方法用于非区域性特定的字符串。如果适合您的用例,区分大小写会更快。

    当您指定 StringComparison.Ordinal StringComparison.OrdinalIgnoreCase ,字符串比较将是非语言的。也就是说,在做出比较决策时,忽略了特定于自然语言的特性。这意味着决策基于简单的字节比较,而忽略由区域性参数化的大小写或等价表。 因此,通过将参数显式设置为 字符串比较.序数 StringComparison.OrdinalIgnoreCase(字符串比较.OrdinalIgnoreCase) ,您的代码通常会加速 ,提高了正确性,并变得更加可靠。

    Source

        4
  •  4
  •   gbro3n    12 年前

    我设计了一个单元测试,使用本文中提到的一些方法来测试字符串比较速度。此测试是使用.NET 4运行的

    简言之,没有太大的差异,我必须进行100000000次迭代才能看到显著的差异。由于字符似乎依次进行比较,直到发现差异,因此不可避免地,字符串的相似性起到了一定的作用。

    这些结果实际上似乎表明使用str1.equals(str2)是比较字符串的最快方法。

    这些是测试的结果,包括测试类:

    ######## SET 1 compared strings are the same: 0
    #### Basic == compare: 413
    #### Equals compare: 355
    #### Equals(compare2, StringComparison.Ordinal) compare: 387
    #### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: 426
    #### String.CompareOrdinal(compare1, compare2) compare: 412
    
    ######## SET 2 compared strings are NOT the same: 0
    #### Basic == compare: 710
    #### Equals compare: 733
    #### Equals(compare2, StringComparison.Ordinal) compare: 840
    #### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: 987
    #### String.CompareOrdinal(compare1, compare2) compare: 776
    
    using System;
    using System.Diagnostics;
    using NUnit.Framework;
    
    namespace Fwr.UnitTests
    {
        [TestFixture]
        public class StringTests
        {
            [Test]
            public void Test_fast_string_compare()
            {
                int iterations = 100000000;
                bool result = false;
                var stopWatch = new Stopwatch();
    
                Debug.WriteLine("######## SET 1 compared strings are the same: " + stopWatch.ElapsedMilliseconds);
    
                string compare1 = "xxxxxxxxxxxxxxxxxx";
                string compare2 = "xxxxxxxxxxxxxxxxxx";
    
                // Test 1
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = compare1 == compare2;
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### Basic == compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 2
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = compare1.Equals(compare2);
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### Equals compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 3
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = compare1.Equals(compare2, StringComparison.Ordinal);
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### Equals(compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 4
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = String.Compare(compare1, compare2, StringComparison.Ordinal) != 0;
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 5
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = String.CompareOrdinal(compare1, compare2) != 0;
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### String.CompareOrdinal(compare1, compare2) compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                Debug.WriteLine("######## SET 2 compared strings are NOT the same: " + stopWatch.ElapsedMilliseconds);
    
                compare1 = "ueoqwwnsdlkskjsowy";
                compare2 = "sakjdjsjahsdhsjdak";
    
                // Test 1
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = compare1 == compare2;
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### Basic == compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 2
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = compare1.Equals(compare2);
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### Equals compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 3
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = compare1.Equals(compare2, StringComparison.Ordinal);
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### Equals(compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 4
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = String.Compare(compare1, compare2, StringComparison.Ordinal) != 0;
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### String.Compare(compare1, compare2, StringComparison.Ordinal) compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
    
                // Test 5
    
                stopWatch.Start();
    
                for (int i = 0; i < iterations; i++)
                {
                    result = String.CompareOrdinal(compare1, compare2) != 0;
                }
    
                stopWatch.Stop();
    
                Debug.WriteLine("#### String.CompareOrdinal(compare1, compare2) compare: " + stopWatch.ElapsedMilliseconds);
    
                stopWatch.Reset();
            }
        }
    }
    
        5
  •  2
  •   buddybubble    7 年前

    这是一个很古老的问题,但既然我发现了它,其他人也可能。

    在进一步研究这个话题时,我发现 interesting blog post 比较字符串比较的所有方法。可能不是很科学,但仍然是很好的户数。

    多亏了这篇文章,我开始在一个场景中使用string.compareordinal,在这个场景中,我必须找出是否有一个字符串在一个由170000个其他字符串组成的列表中,并连续执行这一操作1600次。string.compareordinal使它比string.equals快了近50%。

        6
  •  1
  •   Jaswant Agarwal    15 年前

    我用秒表检查了string.compare和string.compareordinal

        --Compare Ordinal  case 1 
        Stopwatch sw = new Stopwatch();
        sw.Start();
        int x = string.CompareOrdinal("Jaswant Agarwal", "Jaswant Agarwal");
        sw.Stop();
        lblTimeGap.Text = sw.Elapsed.ToString(); 
    
    
    
    
    
    
        -- Only compare  case 2
        Stopwatch sw = new Stopwatch();
        sw.Start();
        int x = string.Compare("Jaswant Agarwal", "Jaswant Agarwal");
        sw.Stop();
        lblTimeGap.Text = sw.Elapsed.ToString();
    

    在案例1中,平均运行时间为00:00:00.0000030 在案例2中,平均运行时间是00:00:00.0000086

    我尝试了不同的相等和不相等的字符串组合,发现每次比较都比只比较快。

    这是我自己的观察结果。你也可以试着在一个表单上放两个按钮,然后复制粘贴这个代码到重定根事件中。

        7
  •  1
  •   tekiegirl    11 年前

    这可能对某些人有用,但是更改我的一行代码使我的方法的单元测试从140ms下降到了1ms!

    原件

    单元测试:140ms

    public bool StringsMatch(string string1, string string2)
    {
        if (string1 == null && string2 == null) return true;
        return string1.Equals(string2, StringComparison.Ordinal);
    }
    

    新的

    单元测试:1ms

    public bool StringsMatch(string string1, string string2)
    {
        if (string1 == null && string2 == null) return true;
        return string.CompareOrdinal(string1, string2) == 0 ? true : false;
    }
    

    单元测试 (NUnb)

    [Test]
    public void StringsMatch_OnlyString1NullOrEmpty_ReturnFalse()
    {
        Authentication auth = new Authentication();
        Assert.IsFalse(auth.StringsMatch(null, "foo"));
        Assert.IsFalse(auth.StringsMatch("", "foo"));
    }
    

    有趣的是,StringsMatch_OnlyString1NullOrEmpty_ReturnFalse()是唯一一个为StringsMatch方法花费140毫秒的单元测试。StringsMatch_AllParamsUnlloRempty_ReturnTrue()始终为1毫秒,StringsMatch_OnlyString2NullOrEmpty_ReturnFalse()始终为1毫秒。

        8
  •  0
  •   WorkRelated    7 年前

    我认为大多数C开发人员比较字符串有几种方法,其中最常见的方法是:

    • Compare -正如你提到的
    • CompareOrdinal -正如你提到的
    • ==
    • String.Equals
    • 编写自定义算法以逐字符比较

    如果你想走极端,你可以使用其他不那么明显的对象/方法:

    • SequenceEqual 例子:

      c1 = str1.ToCharArray(); c2 = str2.ToCharArray(); if (c1.SequenceEqual(c2))

    • IndexOf 例子: if (stringsWeAreComparingAgainst.IndexOf(stringsWeWantToSeeIfMatches, 0 , stringsWeWantToSeeIfMatches.Length) == 0)

    • 或者,您可以实现字典和哈希集,使用字符串作为“键”,并测试它们是否已经存在于要比较的字符串中。例如: if (hs.Contains(stringsWeWantToSeeIfMatches))

    所以,你可以自由地去切骰子,找到你自己的做事方式。请记住,尽管有人将不得不维护代码,而且可能不想花时间试图弄明白为什么要使用您决定使用的任何方法。

    一如既往,优化自己的风险。-)