Linqで1行ずつ与えられた、データを縦に分割しよう!(ToLookup使用)
目的
1行ずつ与えられるデータ(ファイルとか、標準入力とか)が重なって2次元配列みたいなデータを列で分割して、楽に変換したい。
サンプル
例えば、こんなデータがあったとします。
var str = new List<string>()
{
" 1, 2, 3, 4, 5, 6, 7, 8, 9, 10",
" 2, 4, 6, 8, 10, 12, 14, 16, 18, 20",
" 3, 6, 9, 12, 15, 18, 21, 24, 27, 30",
" 4, 8, 12, 16, 20, 24, 28, 32, 36, 40",
" 5, 10, 15, 20, 25, 30, 35, 40, 45, 50",
" 6, 12, 18, 24, 30, 36, 42, 48, 54, 60",
" 7, 14, 21, 28, 35, 42, 49, 56, 63, 70",
" 8, 16, 24, 32, 40, 48, 56, 64, 72, 80",
" 9, 18, 27, 36, 45, 54, 63, 72, 81, 90",
" 10, 20, 30, 40, 50, 60, 70, 80, 90,100",
};
これを列(1列目だと、1,2,3, ... , 10 のように)ごとに取得したい。
for文で
forなら簡単に取得ができる
var sample = new List<string>();
for (int i = 0; i < str.Count; i++)
{
sample.Add(str[i].Split(',')[0]);
}
Console.WriteLine("forサンプル");
Console.WriteLine(string.Join(",", sample));
1列目だけでいいのなら、このサンプルコードでもいいのだけど、複数行対応したいときにはネストをしないといけなくなる。
例えばこんな感じ
//// 1つ目のデータで配列の数を設定
var length = str[0].Split(',').Length;
// 各列のリストを初期化
var sample = new List<List<string>>();
for (int i = 0; i < length; i++)
{
sample.Add(new List<string>());
}
// 1行をカンマで分割し、それぞれのリストに追加していく
for (int i = 0; i < str.Count; i++)
{
var oneLine = str[i].Split(',');
for (int j = 0; j < length; j++)
{
sample[j].Add(oneLine[j]);
}
}
// 表示
for (int i = 0; i < length; i++)
{
Console.WriteLine($"i : {i}");
Console.WriteLine(string.Join(",", sample[i]));
}
冗長な部分もあると思いますが、素直に書いたら大体こんな感じになると思います。意外と長くなってしまいます。
Linqで
次はLinqで書いてみたいと思います。こちらの方がやはり少ない行数で書けるということで、いいですね。慣れるまでは大変ですが。
// 1行をカンマで分割して、0からインデックスを追加
var strWithIndex = str.Select(
x => x.Split(',').Where(word => !string.IsNullOrWhiteSpace(word)).Select((word, i) => new { word, i }));
// 全ての行を平坦化して、先ほど追加したインデックスでグループ化する.
var oneColumnData = strWithIndex.SelectMany(word => word).ToLookup(x => x.i);
一応この2行で、列で取得することが可能です。
実際に取得するとこんな感じです。
foreach (var oneColumn in oneColumnData)
{
Console.WriteLine("キー:" + oneColumn.Key);
Console.WriteLine(string.Join(",", oneColumn.Select(x => x.word)));
}
これで、2次元配列とかも簡単に列で取得することができますね!
簡単な解説
このままで終わるのもあれなので、一応解説をしておきます。
まず、LinqSample.csの1行目はコメントにも書いてある通り、1行をまずカンマで分割し、そのあと分割後の要素が{空、Null、string.Empty}ではない要素のみ取得し、その要素にインデックスを付与しています。
1つだけ実行するとこんな感じ
ここでの、iの値がそのまま列のインデックスとなります。
2つ目は、全部を列挙できるような状態に直してからインデックスでグループを作っていきます。
ToLookupでグループ化した状態は先ほど見せた画像と同じです。
終わりに
いかがだったでしょうか?
次があれば、自分が便利だと思った、C#の標準メソッドなどを紹介したいです。
それではよいC#ライフを!
Author And Source
この問題について(Linqで1行ずつ与えられた、データを縦に分割しよう!(ToLookup使用)), 我々は、より多くの情報をここで見つけました https://qiita.com/pregum/items/9b56dbb273b038605832著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .