2

カスタム文字列分割を書いています。.奇数のバックスラッシュ ( ) が前にないドット ( ) で分割されます\

«string» -> «IEnemerable<string>»
"hello.world" -> "hello", "world"
"abc\.123" -> "abc\.123"
"aoeui\\.dhtns" -> "aoeui\\","dhtns"

元の文字列を(速度のために)再利用する部分文字列があるかどうか、またはこれを高速に実行できる既存の分割があるかどうかを知りたいですか?


input.Split('.')これは私が持っているものですが、 //入力が文字列の場合よりも 2 ~ 3 倍遅くなります。(私はそれが(もう少し複雑な問題であることは知っていますが、それほどではありません)

    public IEnumerable<string> HandMadeSplit(string input)
    {
        var Result = new LinkedList<string>();
        var word = new StringBuilder();
        foreach (var ch in input)
        {
            if (ch == '.')
            {
                Result.AddLast(word.ToString());
                word.Length = 0;
            }
            else
            {
                word.Append(ch);
            }
        }
        Result.AddLast(word.ToString());
        return Result;
    }

LinkedList の代わりに List を使用し、部分文字列の最初と最後を記録し、string.substring を使用して新しい部分文字列を作成します。これは多くのことを行い、string.split とほぼ同じ速度ですが、調整を加えました。(コードを追加します)

4

3 に答える 3

3

あなたが示すループは、パフォーマンスが必要な場合の正しいアプローチです。(正規表現はそうではありません)。

インデックスベースの for ループに切り替えます。試合開始のインデックスを覚えておいてください。個々の文字を追加しないでください。代わりに、コピーする文字の範囲を覚えておいて、Substring項目ごとに 1 回の呼び出しでそれを行います。

また、使用しないでくださいLinkedListListランダム アクセス ミューテーションを除くほとんどすべてのケースで、 よりも低速です。

Listでサイズ変更する通常の配列に切り替えることもできますArray.Resize。これにより、(クラスの一部をメソッドにインライン化したため) 少し面倒なコードにListなりますが、いくつかの小さなオーバーヘッドが削減されます。

次に、 an を返さないでくださいIEnumerable。その項目にアクセスするときに、呼び出し元が間接的に強制されるためです。Listまたは配列を返します。

于 2012-12-11T09:49:41.033 に答える
3

最終的に落ち着いたのがこれです。それはstring.splitほど高速ではありませんが、私がやりたいことをするのに十分であり、変更することができます。

    private IEnumerable<string> HandMadeSplit2b(string input)
    {
        //this one is margenaly better that the second best 2, but makes the resolver (its client much faster), nealy as fast as original.
        var Result = new List<string>();
        var begining = 0;
        var len = input.Length;
        for (var index=0;index<len;index++)
        {
            if (input[index] == '.')
            {
                Result.Add(input.Substring(begining,index-begining));
                begining = index+1;
            }
        }
        Result.Add(input.Substring(begining));
        return Result;
    }
于 2012-12-11T20:58:30.440 に答える
2

そのために使おうとしてはいけませんstring.Split

実装に助けが必要な場合、これを解決する簡単な方法は、文字列をスキャンするループを作成し、修飾ドットを見つけた最後の場所を追跡することです。新しい適格なドットを見つける (または入力文字列の最後に到達する) とyield return、現在の部分文字列だけになります。

編集:リストまたは配列を返すこととyieldを使用することについて

アプリケーションで最も重要なことは、呼び出し元が部分文字列の反復に費やした時間である場合、受け入れられた質問で提案されているように、リストまたは配列にデータを入力して返す必要があります。部分文字列の収集中にサイズ変更可能な配列を使用しないのは、これが遅くなるためです。

一方、全体的なパフォーマンスとメモリに関心があり、呼び出し元がリスト全体を反復処理する必要がない場合は、 を使用する必要がありますyield return。を使用すると、呼び出し元が(直接または間接的に を介して)yield return呼び出すまで、コードがまったく実行されないという利点があります。これは、配列/リストを割り当てるためのメモリを節約し、リストの割り当て/サイズ変更/入力に費やす時間を節約することを意味します。ほとんどの場合、部分文字列を見つけるロジックだけに時間を費やします。これは遅延して行われます。つまり、呼び出し元が部分文字列を反復し続けるため、実際に必要な場合にのみ実行されます。MoveNextforeach

于 2012-12-10T23:22:02.047 に答える