检查特定字符的最佳方法仅出现在字符串中

目标:返回布尔值,指示是否有任何传递的字符不在字符串中。遍历字符串时,如果在字符串索引中包含传递的任何字符,请继续,否则返回false。

下面我有一个可行的解决方案,但是性能对我来说非常重要。

假设:

  • 可以是任何长度的任何字符串。
  • 案例很重要

还有更好的解决方案吗?

我当前的代码和预期的测试用例。

    public static bool ContainsOnlyChars(string strValue,params char[] charValues)
    {
        if (string.IsnullOrEmpty(strValue))
            throw new ArgumentNullException("String cannot be null or empty.");

            for (int i = 0; i < strValue.Length; i++)
            {
                if (!charValues.Any(c=> c == strValue[i]))
                {
                    return false;
                }
            }

            return true;
        }
    }

测试用例看起来像这样,我有很多,但是这里有几个。

// should return true
Console.WriteLine(ContainsOnlyChars("\n",'\n'));
Console.WriteLine(ContainsOnlyChars("\n\n",'\n'));
Console.WriteLine(ContainsOnlyChars("\n\n ",'\n',' '));
Console.WriteLine(ContainsOnlyChars("ab",'a','b'));

Console.WriteLine();

// should return false
Console.WriteLine(ContainsOnlyChars("\nz",'\n')); // because of z
Console.WriteLine(ContainsOnlyChars("z\n\n",'\n')); // because of z
Console.WriteLine(ContainsOnlyChars("\n\n z",' ')); // because of z
Console.WriteLine(ContainsOnlyChars("abz",'b')); // because of z

实际测试用例略有不同,仅采用字符串和固定字符数组。 https://pastebin.com/xS0sRC4n

a3345887 回答:检查特定字符的最佳方法仅出现在字符串中

您当前的解决方案是O(MN),创建您的字符串值的查找并进行检查。

public static bool ContainsOnlyChars(string strValue,params char[] charValues)
{
    if (string.IsNullOrEmpty(strValue))
        throw new ArgumentNullException("String cannot be null or empty.");

    var chrLookup = charValues.ToLookup(c => c);

    for (int i = 0; i < strValue.Length; i++)
    {
        if (!chrLookup.Contains(strValue[i]))
        {
            return false;
        }
    }

    return true;
}
,

相互检查两个列表是O(n * m)的任务,其中n和m是列表的大小。但是,如果两个人都足够长,则可以使用HashSets在其中找到另一个项目。

在您的情况下,您可以使用时间O(n)从原始字符串创建字典,然后使用时间O(m)检查该字典中是否存在其他每个项目,使其成为O(n + m)算法

public static bool ContainsOnlyChars(string strValue,params char[] charValues)
{
    if (string.IsNullOrEmpty(strValue))
        throw new ArgumentNullException("String cannot be null or empty.");

    // The O(n) part
    var dic = new Dictionary<char,bool>();
    foreach (var ch in strValue)
        if (!dic.ContainsKey(ch))
            dic.Add(ch,1);

    // The O(m) part
    foreach (var ch in charValues)
        if(!dic.ContainsKey(ch))
            return false;
    return true;
}

免责声明:我已经在浏览器中编写了代码。

,

要考虑的替代方法是:

public static bool ContainsOnlyChars(string strValue,params char[] charValues)
{
    if (string.IsNullOrEmpty(strValue))
        throw new ArgumentNullException("String cannot be null or empty.");

    return !strValue.Except(charValues).Any();
}

如果false中的任何字符不在strValue中,则代码基本上返回charValues

,

解决方案

您可以简单地解析字符串的字符,并检查所提供的字符是否包含它们。

您将获得最佳的速度和内存性能。

使用扩展方法

static public class StringHelper
{
  static public bool ContainsOnlyChars(this string strValue,params char[] charValues)
  {
    if ( string.IsNullOrEmpty(strValue) )
      throw new ArgumentNullException("String cannot be null or empty.");
    if ( charValues == null )
      throw new ArgumentNullException("Chars cannot be null.");
  for ( int index = 0; index < strValue.Length; index++ )
    if ( !charValues.Contains(strValue[index]) )
        return false;
    return true;
  }
}

短字符串的性能

具有IndexOf

var chrono = new Stopwatch();
chrono.Start();
for ( int index = 0; index < 10000000; index++ )
{
  "This a test string".ContainsOnlyChars('a','b','c','d');
}
chrono.Stop();
Console.WriteLine("Elapsed: " + chrono.ElapsedMilliseconds);
Debug Elapsed: 510
Release Elapsed: 178

随便

Debug Elapsed: 747
Release Elapsed: 281

全部

Debug Elapsed: 1193
Release Elapsed: 644

使用ToLookup

Debug Elapsed: 1542
Release Elapsed: 870

不包含

Debug Elapsed: 2195
Release Elapsed: 1423

带字典

Debug Elapsed: 2947
Release Elapsed: 1900

大字符串性能

具有IndexOf

var random = new Random();
string str = "";
for ( int index = 0; index < 10000; index++)
  str += (char)random.Next(48,127);
chrono.Start();
for ( int index = 0; index < 10000000; index++ )
{
  str.ContainsOnlyChars('a','d','e','f','g','h');
}
chrono.Stop();
Console.WriteLine("Elapsed: " + chrono.ElapsedMilliseconds);
Release Elapsed: 327

随便

Release Elapsed: 469

全部

Release Elapsed: 3733

使用ToLookup

Release Elapsed: 4280

不包含

Release Elapsed: 180562

带字典

Release Elapsed: 284176

Fiddle Snippet Benchmark

注意事项

设计精良的for循环将始终比任何foreach或Linq更快,更不贪心。

证明在IL代码中。

Foreach旨在忘记可能会生成错误的索引管理,但速度稍慢一些。

Linq旨在减少行数并提高可维护性并降低复杂性,但它需要大量的字节,赫兹和时间。

本文链接:https://www.f2er.com/3130324.html

大家都在问