C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

C# CSVHelper仕様で読込位置を初期位置に戻す方法

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■85496 / inTopicNo.1)  C# CSVHelper仕様で読込位置を初期位置に戻す方法
  
□投稿者/ すえぞう (4回)-(2017/10/30(Mon) 15:37:03)

分類:[C#] 

VisualStudio、C#、CSVHelperを使用しています。

以下のようなソースでLoop1の1レコードとLoop2のレコードの内容の突合せをしたいと考えています。
ところが、loop1の1レコード目とLoop2の全レコードと内容比較をしたあと、Loop1の2レコード目以降は
「Loop2はすべて読み込まれた後です」とのことでエラーで止まってしまいます。
Filestreamの場合はfs2.Seek(0, SeekOrigin.Begin);のような感じで読み込み位置のリセットができるそうですが、
CsvReaderの場合のLoop2側の読み込み位置を初期位置に戻す方法を教えてください。

ちなみにやりたいことは、一つのCSVファイル内の別レコードに同じ項目があった場合、ちょっと編集しようと思い、
Loopを2重にして各レコードを突き合わせています。


static void Main(string[] args)
        {
            using (var fs = new FileStream(@"C:\Test\test.csv", FileMode.Open, FileAccess.Read))
            using (var sr = new System.IO.StreamReader(fs, System.Text.Encoding.GetEncoding("shift_jis")))
            using (var rcsv = new CsvReader(sr))

            using (var fs2 = new FileStream(@"C:\Test\test.csv", FileMode.Open, FileAccess.Read))
            using (var sr2 = new System.IO.StreamReader(fs2, System.Text.Encoding.GetEncoding("shift_jis")))
            using (var rcsv2 = new CsvReader(sr2))


            {
                rcsv.Configuration.HasHeaderRecord = false;
                rcsv.Configuration.RegisterClassMap<ReadCsvMapper>();
                var records = rcsv.GetRecords<ReadRecord>();

                rcsv2.Configuration.HasHeaderRecord = false;
                rcsv2.Configuration.RegisterClassMap<ReadCsvMapper2>();
                var records2 = rcsv2.GetRecords<ReadRecord2>();


                foreach (var record in records)
                {

                    Console.WriteLine(recordの中身表示);

                    Console.WriteLine("Loop1");
                    System.Console.ReadLine();

                    foreach (var record2 in records2)
                    {
                        Console.WriteLine(record2の中身表示);

                        Console.WriteLine("Loop2");
                        System.Console.ReadLine();


                    }

                    Console.WriteLine("Loop2 out");
                    System.Console.ReadLine();
                    
                }

                Console.ReadLine();
            }

        }

読み込み位置の初期値戻しもそうですが、もっと簡単にできるよという場合もご教授願います。

引用返信 編集キー/
■85503 / inTopicNo.2)  Re[1]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ もりお (55回)-(2017/10/30(Mon) 20:32:26)
No85496 (すえぞう さん) に返信

レコード全体を配列に入れてぐるぐるやったらいんじゃないでしょうか。
メモリに収まらないとするなら入れ子のループは計算量があれですよ、なんていうか、とにかくやばいです。
引用返信 編集キー/
■85505 / inTopicNo.3)  Re[1]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ Jitta (331回)-(2017/10/31(Tue) 10:04:05)
No85496 (すえぞう さん) に返信

プログラム組んでしなければならないことなのでしょうか。
エクセルに読ませて、ソートすれば、重複は見つけられますよね?
同じように、事前にファイルをソートすれば、
最初から最後まで調べて回るということはしなくても良くなります。
引用返信 編集キー/
■85510 / inTopicNo.4)  Re[2]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ もりお (56回)-(2017/10/31(Tue) 21:30:54)
★配列を使う

var records = csvReader.GetRecords<ReadRecord>().ToArray();
var checks = new bool[records.Length];
for (var i = 0; i < records.Length; i++)
{
    for (var j = i + 1; j < records.Length; j++)
    {
        if (checks[j] == false)
        {
            if (records[i].number == records[j].number)
            {
                checks[j] = true;
                Console.WriteLine("{0} => {1}", records[i].number, records[j].number);
            }
        }
        
    }
}


★Linqを使う

var records = csvReader.GetRecords<ReadRecord>();
var groups = records.GroupBy(record => record.number);
foreach (var group in groups)
{
    if (group.Count() > 1)
    {
        foreach (var record in group)
        {
            Console.WriteLine("{0} => {1}", group.Key, record.number);
        }
    }
}


★Dictionaryを使う

public static class DictionaryExtension
{
    public static void addList<K, V>(this Dictionary<K, List<V>> self, K key, V value)
    {
        List<V> valueList;

        if (self.TryGetValue(key, out valueList) == false)
        {
            valueList = new List<V>();
            self.Add(key, valueList);
        }

        valueList.Add(value);
    }
}

var records = csvReader.GetRecords<ReadRecord>();
var groups = new Dictionary<string, List<ReadRecord>>();

foreach (var record in records)
{
    groups.addList(record.number, record);
}

foreach (var group in groups)
{
    if (group.Value.Count > 1)
    {
        foreach (var record in group.Value)
        {
            Console.WriteLine("{0} => {1}", group.Key, record.number);
        }
    }
}


といった感じで実装はいくつかありそうですね。
データが十分に少なくて行番号を出力したいんだぜといったときは配列をぐるぐる。
データがそれなりにあるときはLinqやDictionaryを使うやり方やJittaさんが紹介されたソートするやり方。
Linqは実質的にGroupByのメソッド呼ぶだけなので超簡単。
というように状況に応じて使い分けるのがいんじゃないでしょうか。

引用返信 編集キー/
■85511 / inTopicNo.5)  Re[3]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ ????a (1回)-(2017/10/31(Tue) 21:47:40)
2017/11/01(Wed) 07:24:00 編集(投稿者)
もりおです。

★ソートを使う

Func<ReadRecord, string> keySelector = record => record.number;

IEnumerable<ReadRecord> records = csvReader.GetRecords<ReadRecord>()
    .OrderBy(keySelector)
    .ToList();

while (records.Any())
{
    var key = keySelector(records.First());

    var group = records.TakeWhile(record => key == keySelector(record));
    var rest = records.Skip(group.Count());

    if (group.Count() > 1)
    {
        foreach (var record in group)
        {
            Console.WriteLine("{0} => {1}", key, record.number);
        }
    }

    records = rest;
}

引用返信 編集キー/
■85512 / inTopicNo.6)  Re[4]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ すえぞう (5回)-(2017/11/01(Wed) 09:57:33)
おはようございます。
一日出てたもので、返事が遅れましてごめんなさい。
Jittaさん、もりおさん、ありがとうございます。

データのレコード数はそれほど多くないのですが、
エクセルは最初に思ったのですが、編集が面倒なので
早々にあきらめました。

教えていただいた方法で考えてみます。
後ほど結果報告いたします。
引用返信 編集キー/
■85513 / inTopicNo.7)  Re[5]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ すえぞう (6回)-(2017/11/01(Wed) 10:37:58)
(あっ、データ編集の話を詳しくしておかないと
何がしたいのかはっきりわからないですね。
読み込み位置の初期値戻しにばかり気を取られていたので
書き忘れていました。)

以下のようなCSVデータを
"a1","b1","c1"
"a1","b1a","c1a"
"a1","b1b","c1b"
"a2","b2","c2"

このように編集したく、わざわざレコード突合せをしようと思った
次第であります。
"a1","b1 b1a b1b","c1 c1a c1b"
"a2","b2","c2"

後出しで申し訳ありません。
引用返信 編集キー/
■85534 / inTopicNo.8)  Re[6]: C# CSVHelper仕様で読込位置を初期位置に戻す方法
□投稿者/ すえぞう (7回)-(2017/11/03(Fri) 18:20:31)
ソートと配列で何とかなりました。
ありがとうございます。
解決済み
引用返信 編集キー/

このトピックをツリーで一括表示


トピック内ページ移動 / << 0 >>

このトピックに書きこむ