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 に答える