私は、さまざまなソースからのデータを処理できる必要があるプログラムを書いています。ソースはさまざまな形式でデータを出力します。したがって、使用されているソースに応じて、列ヘッダーの異なるセットで文字列リストを初期化する必要があります。ヘッダーの数は、データソースに応じて10〜18列で異なります。
基本的に、リストを条件付きで初期化するクリーンな方法が必要です。私には3つの実用的な解決策がありますが、どちらが最もクリーンでベストな方法であるかはわかりません。
これを行うためのより良い/よりクリーンな方法はありますか?そうでない場合、どの例がベストプラクティスですか?
例#1:
List<string> headers = new List<string>();
switch (dataSource)
{
case "Source 1":
headers.Add("header1");
headers.Add("header2");
headers.Add("header3");
headers.Add("...");
headers.Add("header18");
break;
case "Source 2":
headers.Add("headerA");
headers.Add("headerB");
headers.Add("headerC");
headers.Add("...");
headers.Add("headerJ");
break;
default:
// TODO: Handle bad sources.
break;
}
例2:
List<string> headers = new List<string>();
switch (dataSource)
{
case "Source 1":
{
List<string> dataHeaders = new List<string>() { "header1", "header2", "header3", "...", "header18" }
headers = dataHeaders;
break;
}
case "Source 2":
{
List<string> dataHeaders = new List<string>() { "headerA", "headerB", "headerC", "...", "headerJ" }
headers = dataHeaders;
break;
}
default:
{
// TODO: Handle bad sources.
break;
}
}
例3:
List<string> headers = new List<string>();
switch (dataSource)
{
case "Source 1":
headers.AddRange(new List<string>() { "header1", "header2", "header3", "...", "header18" })
break;
case "Source 2":
headers.AddRange(new List<string>() { "headerA", "headerB", "headerC", "...", "headerJ" })
break;
default:
// TODO: Handle bad sources.
break;
}
多くの場合、CSV文字列などのプログラミング言語よりも構文が少ない形式でデータを表現することで、このような問題を本当に解決できます。 C#はわかりませんが、Scalaの例は次のとおりです。
def headersForDataSource(dataSource: String): Option[Array[String]] = {
val headers = """
Source1,header1,header2,header3,...,header18
Source2,headerA,headerB,headerC,...,headerJ
"""
val lines = headers.lines map (_.trim split ',')
lines find (_(0) == dataSource) map (_.tail)
}
これにより、ヘッダーのリストが大幅にコンパクトになり、読みやすくなります。データ構造の構文が乱雑に混ざらないためです。それは、プログラミング言語によってあなたに強制されたフォーマットの代わりに、それをあなたの好みのフォーマットに入れています。
また、switch
を使用してif
およびmaps
を回避することもできます。 Java syntaxisを使用しますが、C#で簡単に実行できると思います
変更不可(静的または定数)記述子
Map<String,String[]> HEADERS_MAP = new HashMap<String,String[]>();
HEADERS_MAP.put("Source 1",new String[]{"header1","headerN"});
HEADERS_MAP.put("Source 2",new String[]{"headerA","headerZ"});
...
//Preventing Map from changes
HEADERS_MAP = Collections.unmodifiableMap(HEADERS_MAP);
注:マップは Dictorinary in C#だと思います
Header builder
//Each consumer will have it's onw list
return Arrays.asList(HEADERS_MAP.get(dataSource));
Edit:最初の回答@unholysamplerのコメントで編集しました。
マップはString []を格納し、builder
は新しいフレッシュ/非バインドリストを返します。そのため、ビルダーコンシューマーはリストのコンテンツを変更でき、コードが不要な変更を行うのを防ぎます。 Collections.unmodificableList
butそうすれば、コードが少し増えて複雑になります。読みにくいコードを実行します。
修正しようとしている問題は何ですか?
パフォーマンスの改善を検討している場合、これは間違いなく時期尚早の最適化のケースです。あなたが与える3つの方法のどれでも、ボタンをクリックした後にマウスから指を離すのにかかるほんの一瞬の何千ものアイテムでリストを満たすことができます。
コードの冗長度を低くするだけの場合は、オプション3のバリエーションが最適です。
var headers = new List<string>();
switch (dataSource)
{
case "Source 1":
headers.AddRange(new [] { "header1", "header2", "header3", "...", "header18" })
break;
case "Source 2":
headers.AddRange(new [] { "headerA", "headerB", "headerC", "...", "headerJ" })
break;
default:
// TODO: Handle bad sources.
break;
}
リストのタイプや要素の配列を指定する必要がないことに注意してください-これらはコンパイラによって自動的に推測されます。
少し変更したオプション2が最善の策だと思います。ヘッダーの宣言はスイッチの外側に残し、スイッチの内側にheaders = new Listを設定するだけです
また、各caseステートメントのブロックを作成するために中括弧は必要ありません。 C#は、各ケースの最後に強制的にブレークさせます。
これを行う利点は、新しいケースを追加した場合、後でそれを使用しようとするとヘッダーが初期化されないという警告が表示されることです。後で追跡するための論理エラーになります。
これは、ペレグリンとカールビーレフェルトの提案を組み合わせた短いバージョンです。
string hline;
switch (dataSource)
{
case "Source 1":
hline = "header1,header2,header3,...,header18";
break;
case "Source 2":
hline = "headerA,headerB,headerC,...,headerZ";
break;
default:
// TODO: Handle bad sources.
break;
}
var headers = new List<string>();
headers.AddRange(hline.Split(','));
連続する間隔からのインデックスによってさまざまなデータソースを参照できる場合、スイッチケース全体をまったく回避し、次のようにhline
を初期化することを検討します。
string hLine = new []{
"header1,header2,header3,...,header18",
"headerA,headerB,headerC,...,headerZ",
"..."}[dataSourceIndex];
辞書を使用しないのはなぜですか?
var headers = new List<string>();
var headersToAdd = new Dictionary<string, string[]>
{
{"Source 1", new string[] {"header1", "header2"} },
{"Source 2", new string[] {"headerA", "headerB"} }
};
headers.AddRange(headersToAdd["Source 1"]);
headers.AddRange(headersToAdd["Source 2"]);