【问题标题】:Fastest search method in StringBuilderStringBuilder 中最快的搜索方法
【发布时间】:2012-08-28 23:41:02
【问题描述】:

我有一个名为stb_Swap_TabuStringBuilder 用于存储课程名称, 我正在使用以下方法查找课程:

stb_Swap_Tabu.ToString.Contains("CourseName")

就我而言,性能是最重要的问题。 有没有更快的方法?

【问题讨论】:

  • 如果您需要使用StringBuilder,那么您可能需要在每次要搜索时调用ToString,这在性能方面并不是一个好主意。 StringBuilder 用于构建字符串;大概如果您正在构建字符串,那么您已经有了组成部分;为什么不直接在这些组成部分中搜索呢?
  • StringBuilder 可能是最不适合存储可搜索名称列表的数据类型。为什么不改用List<string>,而使用ListContains 方法?
  • 你有这个字符串实际上是什么的例子吗?你说它存储“Course's Names” - 无论“Course's”实际上是否意味着“Courses”,“Names”都暗示了多个名称 - 所以大概这是一个以某种方式分隔的字符串。在这种情况下,将其切换为 individual 名称中的 List<string>HashSet<string> 会很有意义
  • HashSet 用于更大数量的字符串,list 用于更小的字符串。
  • 我同意这不太可能是这里需要的。尽管如此,还是会在 StringBuilder 中找到一个子字符串。

标签: c# .net vb.net performance stringbuilder


【解决方案1】:

我知道这是一个老问题,但是当我尝试为自己的项目创建解决方案时,它出现在我的搜索结果中。我以为我需要搜索StringBuilder.ToString 的方法结果,但后来我意识到我可以在StringBuilder 本身上调用方法。我的情况可能和你不一样,但我想分享一下:

Private Function valueFormatter(ByVal value As String) As String
    ' This will correct any formatting to make the value valid for a CSV format
    '
    ' 1) Any value that as a , in it then it must be wrapped in a " i.e. Hello,World -> "Hello,World"
    ' 2) In order to escape a " in the value add a " i.e. Hello"World -> Hello""World
    ' 3) if the value has a " in it then it must also be wrapped in a " i.e. "Hello World" -> ""Hello World"" -> """Hello World"""
    ' 
    ' VB NOTATAION 
    ' " -> """"
    ' "" -> """"""

    If value.Contains(",") Or value.Contains("""") Then
        Dim sb As New StringBuilder(value)
        If value.Contains("""") Then sb.Replace("""", """""")
        sb.Insert(0, """").Append("""")
        Return sb.ToString
    Else
        Return value
    End If
End Function

【讨论】:

    【解决方案2】:

    StringBuilder 并非真正用于所有字符串目的。如果你真的需要搜索一个,你必须编写你自己的方法。

    有几种适合不同情况的字符串搜索算法。

    以下是 Knuth–Morris–Pratt 算法的简单实现,它只关心序数匹配(没有大小写折叠,没有文化相关的排序规则,只是一个普通的代码点到代码点的匹配)。它有一些初始的Θ(m) 开销,其中m 是搜索的单词的长度,然后在Θ(n) 中找到n 是到搜索的单词的距离,或者整个字符串生成器的长度(如果它)不在那里。这胜过简单的逐字符比较,即Θ((n-m+1) m)(其中O() 表示法描述了上限,Θ() 描述了上限和下限)。

    总而言之,听起来创建一个列表可能是完成手头任务的更好方法。

    public static class StringBuilderSearching
    {
      public static bool Contains(this StringBuilder haystack, string needle)
      {
        return haystack.IndexOf(needle) != -1;
      }
      public static int IndexOf(this StringBuilder haystack, string needle)
      {
        if(haystack == null || needle == null)
          throw new ArgumentNullException();
        if(needle.Length == 0)
          return 0;//empty strings are everywhere!
        if(needle.Length == 1)//can't beat just spinning through for it
        {
          char c = needle[0];
          for(int idx = 0; idx != haystack.Length; ++idx)
            if(haystack[idx] == c)
              return idx;
          return -1;
        }
        int m = 0;
        int i = 0;
        int[] T = KMPTable(needle);
        while(m + i < haystack.Length)
        {
          if(needle[i] == haystack[m + i])
          {
            if(i == needle.Length - 1)
              return m == needle.Length ? -1 : m;//match -1 = failure to find conventional in .NET
            ++i;
          }
          else
          {
            m = m + i - T[i];
            i = T[i] > -1 ? T[i] : 0;
          }
        }
        return -1;
      }      
      private static int[] KMPTable(string sought)
      {
        int[] table = new int[sought.Length];
        int pos = 2;
        int cnd = 0;
        table[0] = -1;
        table[1] = 0;
        while(pos < table.Length)
          if(sought[pos - 1] == sought[cnd])
            table[pos++] = ++cnd;
          else if(cnd > 0)
            cnd = table[cnd];
          else
            table[pos++] = 0;
        return table;
      }
    }
    

    【讨论】:

    • 正如@JonHanna 提到的那样,我有充分的理由拥有一个构建器,这就是为什么我的问题标题是:StringBuilder 中最快的搜索方法。作为我的测试的结果,@JonHanna 经过一些修改后提供的答案比使用Conatins 好 28%。我将尝试制作抽象代码并在这里分享。
    • StringBuilder 有一个Replace 函数,它必须不可避免地搜索字符串,甚至获取开始和结束索引,但没有提供indexOf 函数,这是没有意义的。为什么要让我们重做已经完成的事情?
    • 那个代码对我来说失败了,干草堆“abcde”和针“cd”,它返回false。
    • 不应该只是return m;,而不是return m == needle.Length ? -1 : m;吗?
    • @JuriRobl 该位与 -1 的 .NET 约定匹配,表示未找到。不知道是什么原因导致失败,如果有机会我会稍后再看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-03
    • 2011-08-25
    • 2014-10-03
    • 1970-01-01
    • 2013-05-22
    • 2017-12-31
    • 1970-01-01
    相关资源
    最近更新 更多