测试字符是否来自 .NET 中某个类别的最佳方法

本文关键字:方法 最佳 是否 字符 NET 测试 | 更新日期: 2023-09-27 18:34:11

我需要一种有效的方法来测试给定字符(System.Char(是否为辅音。然后我需要元音同样的东西。更一般地说,我需要以下接口的有效实现,因为目标字符集大约有 20 个字符。 请指教。谢谢!

using System;
public interface ITester
{
    Boolean IsInCategory(Char something);
}

更新

好的伙计们,我已经运行了一些测试。这就是我得到的。最好的方法是使用预先计算的映射,其中每个字符都映射到布尔值。(请参阅下面的代码中的索引(。事实证明,HashSet并不是最好的。如果有人有更多想法,请告诉我。

[TestClass]
public class Runner
{
    public const Int32 NumberOfRuns = 10000;
    public const String TextSample = @"The Letter It was November. Although it was not yet late, the sky was dark when I turned into Laundress Passage. Father had finished for the day, switched off the shop lights and closed the shutters; but so I would not come home to darkness he had left on the light over the stairs to the flat. Through the glass in the door it cast a foolscap rectangle of paleness onto the wet pavement, and it was while I was standing in that rectangle, about to turn my key in the door, that I first saw the letter. Another white rectangle, it was on the fifth step from the bottom, where I couldn't miss it. I closed the door and put the shop key in its usual place behind Bailey's Advanced Principles of Geometry. Poor Bailey. No one has wanted his fat gray book for thirty years. Sometimes I wonder what he makes of his role as guardian of the bookshop keys. I don't suppose it's the destiny he had in mind for the masterwork that he spent two decades writing. A letter. For me. That was something of an event. The crisp-cornered envelope, puffed up with its thickly folded contents, was addressed in a hand that must have given the postman a certain amount of trouble. Although the style of the writing was old-fashioned, with its heavily embellished capitals and curly flourishes, my first impression was that it had been written by a child. The letters seemed untrained. Their uneven strokes either faded into nothing or were heavily etched into the paper. There was no sense of flow in the letters that spelled out my name.";
    private interface ITester
    {
        Boolean IsConsonant(Char something);
    }
    // results in millisecs: 14807, 16411, 15050, 
    private class HashSetBasedTester : ITester
    {
        private HashSet<Char> hash;
        public HashSetBasedTester()
        {
            this.hash = new HashSet<Char>("bcdfghjklmnpqrstvwxz");
        }
        public Boolean IsConsonant(Char something)
        {
            return this.hash.Contains(Char.ToLower(something));
        }
    }
    // results in millisecs: 12270, 12495, 12853,
    private class HardcodedTester : ITester
    {
        public Boolean IsConsonant(Char something)
        {
            var lower = Char.ToLower(something);
            return lower == 'b' || lower == 'c' || lower == 'd' || lower == 'f' || lower == 'g' || lower == 'h' || lower == 'j' || lower == 'k' || lower == 'l' || lower == 'm' || lower == 'n' || lower == 'p' || lower == 'q' || lower == 'r' || lower == 's' || lower == 't' || lower == 'v' || lower == 'w' || lower == 'x' || lower == 'z';
        }
    }
    // WORST RESULTS
    // results in millisecs: 32140, 31549, 31856
    private class ListBasedTester : ITester
    {
        private List<Char> list;
        public ListBasedTester()
        {
            this.list = new List<Char> { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'z' };
        }
        public Boolean IsConsonant(Char something)
        {
            return this.list.Contains(Char.ToLower(something));
        }
    }
    // WINNER! (fastest and most consistent)
    // results in millisecs: 11335, 11349, 11386, 
    private class IndexBased : ITester
    {
        private Boolean[] map;
        private char min;
        private char max;
        public IndexBased()
        {
            var chars = "bcdfghjklmnpqrstvwxz".ToArray();
            this.min = chars.Min();
            this.max = chars.Max();
            var length = this.max - this.min + 1;
            this.map = new Boolean[length];
            foreach (var at in chars)
            {
                map[at - min] = true;
            }
        }
        public Boolean IsConsonant(Char something)
        {
            something = Char.ToLower(something);
            return something <= this.max && something >= this.min && this.map[something - this.min];
        }
    }

    [TestMethod]
    public void RunTest()
    {
        var tester = new IndexBased(); // new HashSetBasedTester(); // new HardcodedTester(); // new ListBasedTester(); //
        var stopwatch = Stopwatch.StartNew();
        for (var i = 0; i < NumberOfRuns; i++)
        {
            foreach (var at in TextSample)
            {
                var tested = tester.IsConsonant(at);
            }
        }
        Trace.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
    }
}

更新 2:

这组测试不会对下/高进行铸造,我们有更好的结果!无论如何,收藏夹/输家都是一样的。看看吧:

[TestClass]
public class Runner
{
    public const Int32 NumberOfRuns = 10000;
    public const String TextSample = @"The Letter It was November. Although it was not yet late, the sky was dark when I turned into Laundress Passage. Father had finished for the day, switched off the shop lights and closed the shutters; but so I would not come home to darkness he had left on the light over the stairs to the flat. Through the glass in the door it cast a foolscap rectangle of paleness onto the wet pavement, and it was while I was standing in that rectangle, about to turn my key in the door, that I first saw the letter. Another white rectangle, it was on the fifth step from the bottom, where I couldn't miss it. I closed the door and put the shop key in its usual place behind Bailey's Advanced Principles of Geometry. Poor Bailey. No one has wanted his fat gray book for thirty years. Sometimes I wonder what he makes of his role as guardian of the bookshop keys. I don't suppose it's the destiny he had in mind for the masterwork that he spent two decades writing. A letter. For me. That was something of an event. The crisp-cornered envelope, puffed up with its thickly folded contents, was addressed in a hand that must have given the postman a certain amount of trouble. Although the style of the writing was old-fashioned, with its heavily embellished capitals and curly flourishes, my first impression was that it had been written by a child. The letters seemed untrained. Their uneven strokes either faded into nothing or were heavily etched into the paper. There was no sense of flow in the letters that spelled out my name.";
    private interface ITester
    {
        Boolean IsConsonant(Char something);
    }
    // results in millisecs: 8378, 7980, 7533, 7752
    private class HashSetBasedTester : ITester
    {
        private HashSet<Char> hash;
        public HashSetBasedTester()
        {
            this.hash = new HashSet<Char>("bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ");
        }
        public Boolean IsConsonant(Char something)
        {
            return this.hash.Contains(something);
        }
    }
    // results in millisecs: 6406, 6667, 6500, 6708
    private class HardcodedTester : ITester
    {
        public Boolean IsConsonant(Char something)
        {
            return something == 'b' || something == 'c' || something == 'd' || something == 'f' || something == 'g' || something == 'h' || something == 'j' || something == 'k' || something == 'l' || something == 'm' || something == 'n' || something == 'p' || something == 'q' || something == 'r' || something == 's' || something == 't' || something == 'v' || something == 'w' || something == 'x' || something == 'z' ||
                something == 'B' || something == 'C' || something == 'D' || something == 'F' || something == 'G' || something == 'H' || something == 'J' || something == 'K' || something == 'L' || something == 'M' || something == 'N' || something == 'P' || something == 'Q' || something == 'R' || something == 'S' || something == 'T' || something == 'V' || something == 'W' || something == 'X' || something == 'Z';
        }
    }
    // WORST RESULTS
    // results in millisecs: 36585, 37702, ...
    private class ListBasedTester : ITester
    {
        private List<Char> list;
        public ListBasedTester()
        {
            this.list = new List<Char> { 'b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'z',
                'B', 'C', 'D', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'V', 'W', 'X', 'Z' };
        }
        public Boolean IsConsonant(Char something)
        {
            return this.list.Contains(something);
        }
    }
    // WINNER!
    // results in millisecs: 4716, 4846, 4756, 4550
    private class IndexBased : ITester
    {
        private Boolean[] map;
        private char min;
        private char max;
        public IndexBased()
        {
            var chars = "bcdfghjklmnpqrstvwxzBCDFGHJKLMNPQRSTVWXZ".ToArray();
            this.min = chars.Min();
            this.max = chars.Max();
            var length = this.max - this.min + 1;
            this.map = new Boolean[length];
            foreach (var at in chars)
            {
                map[at - min] = true;
            }
        }
        public Boolean IsConsonant(Char something)
        {
            return something <= this.max && something >= this.min && this.map[something - this.min];
        }
    }

    [TestMethod]
    public void RunTest()
    {
        var tester = new IndexBased();//new IndexBased(); // new HashSetBasedTester(); // new HardcodedTester(); // new ListBasedTester(); //
        var stopwatch = Stopwatch.StartNew();
        for (var i = 0; i < NumberOfRuns; i++)
        {
            foreach (var at in TextSample)
            {
                var tested = tester.IsConsonant(at);
            }
        }
        Trace.WriteLine(stopwatch.ElapsedMilliseconds.ToString());
    }
}

测试字符是否来自 .NET 中某个类别的最佳方法

HashSet<char>就可以了。为辅音、元音等创建单独的实例,并使用它们来测试成员资格。

ISet<char> vowels = new HashSet<char>("auoie");
if (vowels.Contains('a')) {
    // ...
}

更新 :对于英文字符子集,您可以构建一个bool数组 - 类似于您在更新中使用的数组,但没有偏移量 min ,并且大写/小写重复:它会更快 - 几乎和它得到的一样快。

private class IndexBased : ITester {
    private readonly bool[] map = new bool[128];
    public IndexBased() {
        foreach (var ch in "bcdfghjklmnpqrstvwxz") {
            map[ch] = map[Char.ToUpper(ch)] = true;
        }
    }
    public bool IsConsonant(Char ch) {
        return ch < map.Length && map[ch];
    }
}

我给了 dasblinenlight 一个 +1,但如果您需要不区分大小写,那么

private HashSet<string> vowels = new HashSet<string>(StringComparer.CurrentCultureIgnoreCase);

可能会提供更好的性能。

据我所知,没有快速简单的不区分大小写的字符比较。 如果有,请告诉我。

我尝试了以下方法,这是一个死热

HashSet

consonantHSchar = new HashSet { 'B', 'C', 'D', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T','V', 'W', 'X', 'Y', 'Z', 'b', 'c', 'd', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z' }; 列表辅音列表字符 = 新列表 { 'B', 'C', 'D', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T','V', 'W', 'X', 'Y', 'Z', 'b', 'c', 'd', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'v', 'w', 'x', 'y', 'z' }; HashSet consonantHSstring = new HashSet(StringComparer.CurrentCultureIgnoreCase( { "B">

, "C", "D", "F", "G", "H", "I", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T","V", "W", "X", "Y", "Z" };
Stopwatch sw = new Stopwatch();
sw.Start();
if (consonantHSchar.Contains('b')) Debug.WriteLine("consonantHSchar.Contains('b')");
if (consonantHSchar.Contains('m')) Debug.WriteLine("consonantHSchar.Contains('m)");
if (consonantHSchar.Contains('z')) Debug.WriteLine("consonantHSchar.Contains('z')");
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds.ToString());
sw.Restart();
if (consonantListchar.Contains('b')) Debug.WriteLine("consonantListchar.Contains('b')");
if (consonantListchar.Contains('m')) Debug.WriteLine("consonantListchar.Contains('m')");
if (consonantListchar.Contains('z')) Debug.WriteLine("consonantListchar.Contains('z')");
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds.ToString());
sw.Restart();
if (consonantHSstring.Contains("b")) Debug.WriteLine("consonantHSstring.Contains('b')");
if (consonantHSstring.Contains("m")) Debug.WriteLine("consonantHSstring.Contains('m')");
if (consonantHSstring.Contains("z")) Debug.WriteLine("consonantHSstring.Contains('z')");
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds.ToString());
sw.Restart();
if (consonantListchar.Contains('b')) Debug.WriteLine("consonantListchar.Contains('b')");
if (consonantListchar.Contains('m')) Debug.WriteLine("consonantListchar.Contains('m')");
if (consonantListchar.Contains('z')) Debug.WriteLine("consonantListchar.Contains('z')");
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds.ToString());
sw.Restart();
if (consonantHSchar.Contains('b')) Debug.WriteLine("consonantHSchar.Contains('b')");
if (consonantHSchar.Contains('m')) Debug.WriteLine("consonantHSchar.Contains('m)");
if (consonantHSchar.Contains('z')) Debug.WriteLine("consonantHSchar.Contains('z')");
sw.Stop();
Debug.WriteLine(sw.ElapsedMilliseconds.ToString());