简体   繁体   English

如何加快 c# 中的 indexof?

[英]How can I speed up indexof in c#?

Here are two strings:这里有两个字符串:

string a="abcdefghijklmnopqrstuvwxyz";
string A="ABCDEFGHIJKLMNOPQRSTUVWXYZ";

The strings have 1500 characters and each character in the string is unique and constant.字符串有 1500 个字符,字符串中的每个字符都是唯一且恒定的。

When there is an article, I have to get the index in a of each character in it.当有一篇文章时,我必须获取其中每个字符a索引。 And then return the corresponding index of the character in A .然后返回A中字符的对应索引。

For example:例如:

If the article is "Here is an article", it will return "HERE IS AN ARTICLE".如果文章是“这是一篇文章”,它将返回“这是一篇文章”。

What I want to do is not just character uppercase.我想做的不仅仅是字符大写。 I am not allowed to show the source code, so I can only show an example that is alike to my project.我不允许展示源代码,所以我只能展示一个与我的项目相似的例子。 Please excuse this.请原谅。

The List way:列表方式:

public string Translate(string i)
{
    DateTime DT = DateTime.Now;
    StringBuilder SB = new StringBuilder();
    foreach (char c in i)
    {
        int j = a.IndexOf(c);
        if (j != -1)
        {
            SB.Append(A[j]);
        }
        else
        {
            SB.Append(c.ToString());
        }
    }
    Debug.WriteLine("Time:" + (DateTime.Now - DT).TotalMilliseconds + "ms");
    return SB.ToString();
}

I tried to use an article that is 4000 characters in length to test it.我尝试使用一篇 4000 个字符的文章来测试它。 It spends 400ms to finish it.它花费了 400 毫秒来完成它。

I want to speed this up.我想加快速度。 I considered Dictionary or List may be faster, so I modified the code like this:我认为DictionaryList可能会更快,所以我修改了如下代码:

The Dictionary way:字典方式:

public static List<T> d = new List<T>();

public class T 
{
    public string s;
    public string t;
}       

public static string Translate(string i)
{
    if (d.Count == 0)
    {
        foreach (char c in a)
        {
            int o = a.IndexOf(c);
            d.Add(new T() { s = c.ToString(), t = A[o].ToString() });
        }
    }
    DateTime DT = DateTime.Now;
    StringBuilder SB = new StringBuilder();
    foreach (char c in i)
    {
        var Elements = d.Where(X => X.s == c.ToString());
        if (Elements.Count() == 0)
        {
            SB.Append(c.ToString());
        }
        else
        {
            SB.Append(Elements.FirstOrDefault().t);
        }
    }
    Debug.WriteLine("Time:" + (DateTime.Now - DT).TotalMilliseconds + "ms");
    return SB.ToString();
}

Finally, it spends about 20s to finish it, much more than using the IndexOf method.最后,它花费了大约 20 秒来完成它,比使用IndexOf方法要多得多。 I tried the Dictionary way after that and found it wastes much more time than List .之后我尝试了Dictionary方式,发现它比List浪费更多时间。 Obviously Dictionary and List is not the right way.显然DictionaryList不是正确的方法。

I wonder if there is any way for me to make it faster?我想知道有什么方法可以让我更快吗? Thank you.谢谢你。

I would try using Dictionary<char, char> for mapping and using char array and string ctor accepting one instead of StringBuilder :我会尝试使用Dictionary<char, char>进行映射并使用 char 数组和string ctor 接受一个而不是StringBuilder

static string A = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

static Dictionary<char, char> Mapped = "abcdefghijklmnopqrstuvwxyz".Select((c, i) => (c, As: A[i])).ToDictionary(x => x.c, x => x.As);

public static string Translate(string s)
{
    DateTime DT = DateTime.Now;
    var res = new char[s.Length];
    for (int i = 0; i < s.Length; i++)
    {
        var c = s[i];
        if(Mapped.ContainsKey(c))
        {
            res[i] = Mapped[c];
        }
        else
        {
            res[i] = c;
        }
    }

    Debug.WriteLine("Time:" + (DateTime.Now - DT).TotalMilliseconds + "ms");
    return new string(res);
}

Also to benchmark this kind of code personally I prefer to use BenchmarkDotNet .另外,为了亲自对此类代码进行基准测试,我更喜欢使用BenchmarkDotNet

How about putting the string a into a dictionary with the character as the key and the mapped value from A as the value.如何将字符串a放入字典中,以字符作为键,将A中的映射值作为值。

void Main()
{
    Translate("Hej").Dump();
}
const string A = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
static Dictionary<char, char> a = "abcdefghijklmnopqrstuvwxyz"
                                     .Select((c, i) => (c, i))
                                     .ToDictionary(x => x.c, x => A[x.i]);


public string Translate(string i)
{
    DateTime DT = DateTime.Now;
    StringBuilder SB = new StringBuilder(i.Length);
    foreach (char c in i)
    {
        if (a.TryGetValue(c, out var r))
        {
            SB.Append(r);
        }
        else
        {
            SB.Append(c.ToString());
        }
    }
    Debug.WriteLine("Time:" + (DateTime.Now - DT).TotalMilliseconds + "ms");
    return SB.ToString();
}

If you want speed and string a and A have the same length... Then this might be what you want.如果您希望速度和字符串aA具有相同的长度......那么这可能就是您想要的。

        private static string a = "abcdefghijklmnopqrstuvwxyz";
        private static string A = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

        public static unsafe void MakeWeirdStuff(string value)
        {
            if (value == null || value.Length == 0)
            {
                return;
            }

            fixed (char* chr = value)
            {
                for (int i = 0; i < value.Length; i++)
                {
                    char valueChar = *(chr + i);
                    int index = a.IndexOf(valueChar);

                    if (index >= 0)
                        *(chr + i) = A[index];
                }
            }
        }
    

Don't forget to allow unsafe code in your project and compile it in "Release" mode with optimization turned on.不要忘记在您的项目中允许不安全代码并在“发布”模式下编译它并打开优化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM