2011-04-16 3 views
3

"$0Option one$1$Option two$2$Option three"(など)の文字列には、各数値がオプションに対応する辞書に変換したいという文字列があります。私は現在、この問題の解決策を持っていますが、このメソッドはインポートするすべてのエントリ(数千個)に対して呼び出されるので、できるだけ最適化します。正規表現を使用した辞書への文字列(最適化したい)

public Dictionary<string, int> GetSelValsDictBySelValsString(string selectableValuesString) 
{ 
    // Get all numbers in the string. 
    var correspondingNumbersArray = Regex.Split(selectableValuesString, @"[^\d]+").Where(x => (!String.IsNullOrWhiteSpace(x))).ToArray(); 

    List<int> correspondingNumbers = new List<int>(); 

    int number; 
    foreach (string s in correspondingNumbersArray) 
    { 
     Int32.TryParse(s, out number); 
     correspondingNumbers.Add(number); 
    } 

    selectableValuesString = selectableValuesString.Replace("$", ""); 

    var selectableStringValuesArray = Regex.Split(selectableValuesString, @"[\d]+").Where(x => (!String.IsNullOrWhiteSpace(x))).ToArray(); 

    var selectableValues = new Dictionary<string, int>(); 

    for (int i = 0; i < selectableStringValuesArray.Count(); i++) 
    { 
     selectableValues.Add(selectableStringValuesArray.ElementAt(i), correspondingNumbers.ElementAt(i)); 
    } 

    return selectableValues; 
} 
+0

すべてのキーとすべての値の間に '$'記号がありますか?あなたの例では、1つの '$'が意図的に、または間違っていますか?意図的に – NOtherDev

+0

。 $ 0オプション$ 1 $オプション$ 2 $オプション$ 3 $オプション$ 4 $オプション.....など私は整数をキーとするべきであることを認識しています(文字列が等しい場合)。 – SimonW

答えて

3

あなたのコードで私の注目を集めた最初のものは、それが入力された文字列を3回処理していることである:二回Replace()Split()と一度に。 Matches()メソッドは、このジョブのSplit()よりもはるかに優れたツールです。それを使用すると、必要なものすべてを1回のパスで抽出できます。コードを読みやすくすることもできます。

私が気付いたのは、すべてのループと中間オブジェクトです。すでにLINQを使用しています。 実際にはを使用すると、そのすべてのクラッタを排除することができますパフォーマンスを向上させます。それをチェックアウト:

public static Dictionary<int, string> GetSelectValuesDictionary(string inputString) 
{ 
    return Regex.Matches(inputString, @"(?<key>[0-9]+)\$*(?<value>[^$]+)") 
    .Cast<Match>() 
    .ToDictionary(
     m => int.Parse(m.Groups["key"].Value), 
     m => m.Groups["value"].Value); 
} 

ノート:MatchCollectionのみIEnumerableとしての地位をアドバタイズし、我々はそれがIEnumerable<Match>する必要があるため

  • Cast<Match>()が必要です。
  • \dの代わりに[0-9]を使用しましたが、あなたの値に非ラテン文字体系の数字が含まれている可能性があります。 .NETで\dはすべて一致します。
  • Matches()のような静的Regexメソッドは、Regexオブジェクトを自動的にキャッシュしますが、このメソッドを多く呼び出す場合(特に、他の多くの正規表現も使用している場合は特に)、静的なRegexオブジェクトとにかくパフォーマンスが本当に重要な場合は、Compiledオプションを指定することができます。
  • あなたのコードのように、私のコードは不正な入力を処理しようとしません。特に、鉱山は数字が大きすぎると例外がスローされますが、あなたのものはゼロに変換されます。これはおそらくあなたの実際のコードとは関係ありませんが、戻り値をチェックせずにTryParse()と呼んでいることに不安を感じるように感じました。 :/
  • また、キーが一意でないことを確認しないでください。 @Gabeのように、私は一意になり、文字列の値がなかったので、数値の値をキーとして使いました。私はそれもあなたの実際のデータには問題ではないと信じています。;)
+0

うわー、元のコードよりずっと簡単です。ありがとう。私のお母さんが私に言わなかったとしても、今試合で遊んでいると思うよ) – SimonW

+0

ええ、私は実際に.NET言語でプログラミングしたことがないので、このようなことの多くが私を驚かせました。私はこれに慣れることができた! –

2

selectableStringValuesArrayは実際には配列ではありません。つまり、それにインデックスを付けるたびに(ElementAtでカウントするか、またはCountと数えます)、正規表現を再実行し、空白以外のものを検索します。代わりに、このようなものが必要:

var selectableStringValuesArray = Regex.Split(selectableValuesString, @"[\d]+").Where(x => (!String.IsNullOrWhiteSpace(x))).ToArray();

それは同じ問題を抱えているので、あなたはまた、あなたのcorrespondingNumbersStringを修正する必要があります。

あなたはC#4を使用していますので、Zipを使用してリストを結合してから、配列を作成したり、ループを使用したりする必要はありません。あなたはこのようなあなたの辞書を作成することができます。

return correspondingNumbersString.Zip(selectableStringValuesArray, 
     (number, str) => new KeyValuePair<int, string>(int.Parse(number), str)) 
     .ToDictionary(kvp => kvp.Key, kvp => kvp.Value); 
+0

配列を使用するようにコードを更新しました。ありがとう。 – SimonW

+0

ジップソリューションでうまく答えました。 Zipを使用するとパフォーマンスが向上するはずですか?私がクレジットを持っていれば、私はあなたにランクを付けます。 – SimonW

+0

@Simon: 'zip'を使うのは、実際の配列作成ステップを避けるため、配列を使うよりもわずかに*速くすべきです。 – Gabe

関連する問題