アイデアは次のとおりです:
大規模なダミー CSV (100 万行) に顧客データのサンプルが含まれているとすると、以下の目標で処理を実行します。
顧客のサンプル CSV はここからダウンロードできます https://github.com/datablist/sample-csv-files
- CSV からデータを抽出します
- データ/行数を計算します
- 各都市の顧客数をグループ化
- 顧客数の多い順に都市を並べ替えます
- 処理時間を計算する
データのロードと抽出
// open the file to a reader interface c, err := os.Open("../data/customers-1000000.csv") if err != nil { log.Fatal(err) } defer c.Close() // load file reader into csv reader // Need to set FieldsPerRecord to -1 to skip fields checking r := csv.NewReader(c) r.FieldsPerRecord = -1 r.ReuseRecord = true records, err := r.ReadAll() if err != nil { log.Fatal(err) }
各形式でフィールドまたは列の数が異なる可能性があるため、行のフィールドチェックをスキップしたいため、FieldsPerRecord を -1 に設定しますこの状態では、CSV からすべてのデータをロードして抽出することができており、次の処理状態に進む準備ができています。また、関数 len(records) を使用すると、CSV 内の行数を知ることができます。
総顧客数を各都市にグループ化
["Jakarta": 10, "Bandung": 200, ...]
// create hashmap to populate city with total customers based on the csv data rows // hashmap will looks like be ["city name": 100, ...] m := map[string]int{} for i, record := range records { // skip header row if i == 0 { continue } if _, found := m[record[6]]; found { m[record[6]]++ } else { m[record[6]] = 1 } }
これで、都市のコレクションとその中に含まれる顧客の数を含むマップ m ができました。この時点で、都市ごとに何人の顧客をグループ化するかという問題はすでに解決しています。
最大合計顧客の並べ替え
// convert to slice first for sorting purposes dc := []CityDistribution{} for k, v := range m { dc = append(dc, CityDistribution{City: k, CustomerCount: v}) }
バブル ソートは、隣接する要素の順序が間違っている場合に繰り返し入れ替えることで機能する最も単純な並べ替えアルゴリズムです。このアルゴリズムは、平均および最悪の場合の時間計算量が非常に高いため、大規模なデータセットには適していません。参考: https://www.geeksforgeeks.org/bubble-sort-algorithm/
スライスを使用して、データをループし、インデックスの次の値をチェックし、現在のデータが次のインデックスより小さい場合はそれを交換します。詳細なアルゴリズムは参考サイトで確認できます。
並べ替えプロセスは次のようになります
// open the file to a reader interface c, err := os.Open("../data/customers-1000000.csv") if err != nil { log.Fatal(err) } defer c.Close() // load file reader into csv reader // Need to set FieldsPerRecord to -1 to skip fields checking r := csv.NewReader(c) r.FieldsPerRecord = -1 r.ReuseRecord = true records, err := r.ReadAll() if err != nil { log.Fatal(err) }
ループの終わりまでに、最後のスライスからソートされたデータが得られます。
処理時間の計算は非常に簡単で、プログラムのメイン処理の実行前後のタイムスタンプを取得し、その差分を計算します。 Go では、アプローチは十分に単純である必要があります。
["Jakarta": 10, "Bandung": 200, ...]
コマンドでプログラムを実行します
// create hashmap to populate city with total customers based on the csv data rows // hashmap will looks like be ["city name": 100, ...] m := map[string]int{} for i, record := range records { // skip header row if i == 0 { continue } if _, found := m[record[6]]; found { m[record[6]]++ } else { m[record[6]] = 1 } }
出力されるのは、行数、ソートされたデータ、および処理時間です。以下はこのようなものです:
期待通りの Go パフォーマンスで、100 万行の CSV を 1 秒以内に処理しました!
完成したコードはすべて私の Github リポジトリですでに公開されています:
https://github.com/didikz/csv-processing/tree/main/golang
CSV を抽出したすべてのレコードをループしてマップし、ReadAll() ソースでチェックすると、指定されたファイル リーダーに基づいてスライスを作成するループも含まれているため、現在のソリューションをさらに最適化できるかもしれないと考えていました。これにより、100 万行で 100 万のデータに対して 2 つのループが生成される可能性があり、これは好ましくありません。
ファイル リーダーから直接データを読み取ることができれば、そこからマップを直接作成できるため、必要なループは 1 つだけであると考えました。ただし、レコードのスライスは他の場所で使用されますが、この場合は使用されません。
まだそれを理解する時間がありませんが、手動で行う場合のマイナス面も考えました:
コーディングを楽しんでください!
以上がGo を使用した大規模な CSV 処理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。