0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

gocsvで読み込んだデータに手を加えて構造体に入れたい

Posted at

やりたいこと

タグでcsvを読み取りたいのを大前提として、
csvの行としては分けられているデータを加工して(結合するなど)csvを読み込みたい
例として以下のようなcsvの姓と名を結合して構造体に持ちたいことがあった。

姓,名,年齢,職業
山田,太郎,30,エンジニア
佐藤,花子,25,デザイナー
田中,一郎,35,医師
渡辺,和子,28,教師
高橋,健二,32,自由業

実現手段

github.com/gocarina/gocsvのUnmarshalBytesToCallbackを使用する。
CSVの列に対応する構造体を定義しておいて、一度その形式でデータを受け取ってから欲しい形式に加工する形。

思ったよりは簡単に実装できるが実装サンプルが見つけられなかったので備忘録として。

コード例

ヘッダ部分の諸々は省略

type (
	Person struct {
		Name string
		Age  int
		Job  string
	}
	// 大文字にしないとgocsvから見えない
    // csvの形式の構造体を定義しておく
	PersonCSV struct {
		FirstName  string `csv:"名"`
		SecondName string `csv:"姓"`
		Age        int    `csv:"年齢"`
		Job        string `csv:"職業"`
	}
)

func main() {
	test := `姓,名,年齢,職業
	山田,太郎,30,エンジニア
	佐藤,花子,25,デザイナー
	田中,一郎,35,医師
	渡辺,和子,28,教師
	高橋,健二,32,自由業`

	var p []Person
	if err := gocsv.UnmarshalBytesToCallback([]byte(test), func(pc PersonCSV) {
		p = append(p, Person{
			Name: pc.FirstName + pc.SecondName,
			Age:  pc.Age,
			Job:  pc.Job,
		})
	}); err != nil {
		log.Fatalln(err)
	}
	for _, v := range p {
		fmt.Println(v)
	}
}

func (p Person) String() string {
	return fmt.Sprintf("%s(%d) %s", p.Name, p.Age, p.Job)
}

コールバック関数が複雑になるとき

コールバック関数が複雑になるときは以下の対処法がありそう

  1. globalに[]Personを持たせる(あまりイケてなさそう)
  2. コールバック用の関数を返す関数を別で定義
  3. 無名関数で呼ぶための関数を定義

2の実装

// 処理が複雑な場合は関数を返すようにする
func ComplexProcess(person *[]Person) func(PersonCSV) {
	return func(pc PersonCSV) {
		*person = append(*person, Person{
			Name: pc.FirstName + pc.SecondName,
			Age:  pc.Age,
			Job:  pc.Job,
		})
		// さらに何らかの処理。。。
	}
}

func main() {
    ...
	var p2 []Person
	cp := ComplexProcess(&p2)
	if err := gocsv.UnmarshalBytesToCallback([]byte(test), cp); err != nil {
		log.Fatalln(err)
	}
	for _, v := range p2 {
		fmt.Println(v)
	}
    ...
}

3の実装

func ComplexProcess2(person *[]Person, personCSV PersonCSV) {
	// pに値を加工して代入するような何らかの複雑な処理
	*person = append(*person, Person{
		Name: personCSV.FirstName + personCSV.SecondName,
		Age:  personCSV.Age,
		Job:  personCSV.Job,
	})
}

func main() {
    ...
	var p3 []Person
	if err := gocsv.UnmarshalBytesToCallback([]byte(test), func(pc PersonCSV) {
		ComplexProcess2(&p3, pc)
	}); err != nil {
		log.Fatalln(err)
	}
	for _, v := range p3 {
		fmt.Println(v)
	}
    ...
}

ざっくり書いたのは以下。
https://github.com/lapis2411/go-evaluation/blob/main/gocsv.go

よりよさげな対応あればコメントなどで教えて頂ければ!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?