1

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

using System;

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

更新

好的,伙计们,我已经进行了一些测试。这就是我得到的。最好的方法是使用预先计算的映射,其中每个字符都映射到布尔值。(请参阅下面代码中的 IndexBased)。事实证明,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());
    }
}
4

2 回答 2

5

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];
    }
}
于 2012-05-15T19:23:01.027 回答
1

我给了 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' }; List consonantListchar = new List { '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”};'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”};'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”};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”};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”};,'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”};,'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());
于 2012-05-15T19:44:26.633 回答