LoginSignup
1
0

More than 3 years have passed since last update.

pythonのcsvモジュールで詰まった話

Posted at

この記事について

python勉強中です。

csvモジュール縛りで色々やろうとしたところ、詰まってしまったので備忘録。
「pandas使えよ」って5回くらい思われるだろうなって感じですが、csvモジュール縛りに意味があるんだ!ということでやっておりました。はい。
いやその縛り意味あんのかよって言われると、そこは、もう、はい、すみません。

やりたかったこと

csvモジュールしか使わない、という前提のもと、
既存のcsvファイルにカウントアップで上書きする。

csvファイルにはNAMEとCOUNTという列があり、
NAMEにはレストランの名前が、COUNTには数字が入る。

●CSVの例
NAME,COUNT
sukiya,1
matsuya,1
yoshinoya,2

最初に書いたコード

csv_train.py

import csv

fieldnames =  ["NAME", "COUNT"]

# CSVファイルを読み取りで開く。また、行数を数えておく。
with open("csv_train.csv", "r", newline="") as csv_file:
    reader = csv.DictReader(csv_file)
    reader_list = list(reader)
    rows_cnt = len(reader_list)

# CSVにデータがあれば、レコメンドを出す
if rows_cnt >= 1:
    # 今何行目を読んでいるのかのカウント変数
    t = 1
    for row in reader_list:
        print("My recommended retaurant is " + row["NAME"] + ".")
        print("Do you like this restaurant? [Yes/No]")
        ans = input()

        # レコメンドに対してユーザーが「好き」と答えたら
        if ans == "Yes":
            with open("csv_train.csv", "w", newline="") as csv_file:
                writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
                writer.writeheader()
                i = 1
                for row in reader_list:
                    if i == t:
                        cnt = int(row["COUNT"]) + 1
                        writer.writerow({"NAME": row["NAME"], "COUNT": cnt})
                    else:
                        writer.writerow({"NAME": row["NAME"], "COUNT": row["COUNT"]})
                    i += 1

        # レコメンドに対してユーザーが「好きではない」と答えたら
        else:
            pass

        # カウント変数をカウントアップ
        t += 1

# お礼を言ってクローズ
print("Have a good day!")

何がしたいコードなのか

CSVモジュールを使ったデータの上書きについて、一行目から順番に更新していく、というやり方しか見当たらなかった(たぶん調べ方が悪いのだろう)。
なので、更新したい行数を指定してあげて、その行は更新するが、それ以外の行は元のデータの内容で上書き、という処理にした。

だいぶ頭の悪い処理だけど、他に思いつかなかった…

何が起きるか?

データの最終行しかカウントアップされない。

なぜか?

一番最初にcsvを読み込むときに、reader_listにcsvの中身を格納している。
また、書き込む際もreader_listに対してforを回して処理しようとしている。
だけど、このreader_listは最初に読み込んだ際のreader_listなので、
書き込み処理をする都度、一番最初のCSVの内容に戻ってしまう。

結果、一番最後の書き込み処理しか反映されないことになる。

どうしたらいいのか?

書き込み処理をする都度、reader_listを更新してあげればよい。

csv_train.py

import csv

fieldnames =  ["NAME", "COUNT"]

# CSVファイルを読み取りで開く。また、行数を数えておく。
with open("csv_train.csv", "r", newline="") as csv_file:
    reader = csv.DictReader(csv_file)
    reader_list = list(reader)
    rows_cnt = len(reader_list)

# CSVにデータがあれば、レコメンドを出す
if rows_cnt >= 1:
    # 今何行目を読んでいるのかのカウント変数
    t = 1
    for row in reader_list:
        print("My recommended retaurant is " + row["NAME"] + ".")
        print("Do you like this restaurant? [Yes/No]")
        ans = input()

        # レコメンドに対してユーザーが「好き」と答えたら
        if ans == "Yes":

            #この処理を追加。書き込み前にreader_listを新しいのに変える。
            with open("csv_train.csv", "r", newline="") as csv_file:
                reader = csv.DictReader(csv_file)
                reader_list = list(reader)

            with open("csv_train.csv", "w", newline="") as csv_file:
                writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
                writer.writeheader()
                i = 1
                for row in reader_list:
                    if i == t:
                        cnt = int(row["COUNT"]) + 1
                        writer.writerow({"NAME": row["NAME"], "COUNT": cnt})
                    else:
                        writer.writerow({"NAME": row["NAME"], "COUNT": row["COUNT"]})
                    i += 1

        # レコメンドに対してユーザーが「好きではない」と答えたら
        else:
            pass

        # カウント変数をカウントアップ
        t += 1

# お礼を言ってクローズ
print("Have a good day!")

感想

CSVモジュールを使ったデータの更新処理が、ほんとにこういうやり方しかないのか?と思いながら書いてた。なんか無理やり解決した感がすごい。
「こういうの熟練の皆様はどういう風に書くのだろう」という興味で、コメントが貰えれば万々歳、スルーされてもやむなし、くらいの気持ちで、Qiita初投稿してみました。

初めて書いた記事がほんとにこれでいいのだろうか自分。あとで消したくなったりしないだろうか自分。どうだろうか自分。

なにはともあれ、最後まで読んでくださった方、有難うございました。

1
0
2

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
1
0