質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.86%

[Python]csvで一部のデータをカウントアップして更新したい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 941

kei-kappa564

score 13

 前提・実現したいこと

コードを実行するとおすすめのレストラン名を聞かれます。
おすすめのレストラン名の質問に対しての回答はrestaurant.csvにて、
"Name"キーと"Count"キーにて保存されます。
"Name"キーには質問の回答のレストラン名が入り、
"Count"キーには質問に対しての回答で何回そのレストラン名が出てきたかをカウントします。

 発生している問題・エラーメッセージ

初めて名前が出てきたレストランはしっかりとcsvに記録がされるのですが、
二回目以降名前が出てきたレストラン名に関しては上手く"Count"キーがカウントアップされません、
何故でしょうか。

 該当のソースコード

import csv
import os


print("#####################################################")
print("どこのレストランが好きですか?")
print("#####################################################")
restaurant = input()

# csvファイルが無かったら作成+書き加える→else、在ったら書き加える→if。
if os.path.exists("restaurant.csv"):
    with open("restaurant.csv", "r+", newline='') as res_csv:
        fieldnames = ["Name", "Count"]
        writer = csv.DictWriter(res_csv, fieldnames=fieldnames)
        # addはレストランの名前があるか否かのトリガー
        restaurant_is_exist = False
        # res_csvをfor文でListにできるように変換
        new_csv = csv.reader(res_csv)
        for row in new_csv:
            print(row) # ここのrowはlist型
            if (restaurant in row) == True:
                print(int(row[1]) + 1)
                row[1] = int(row[1]) + 1
                print("Restaurant is Exist")
                restaurant_is_exist = True
        if restaurant_is_exist == False:
            writer.writerow({"Name": restaurant, "Count": 1})
            print("Restaurant is not Exist")
    print("If")
else:
    with open("restaurant.csv", "w", newline='') as res_csv:
        fieldnames = ["Name", "Count"]
        writer = csv.DictWriter(res_csv, fieldnames=fieldnames)
        writer.writeheader()
        writer.writerow({"Name": restaurant, "Count": 1})
    print("Else")

 試したこと

コード中の、

print(int(row[1]) + 1)


で、実際にカウントアップ出来るのかを確認したりしてみたのですが、
カウントアップは出来ているようでした、しかしそれがrestaurant.csvには反映されていないようです。

 補足情報

restaurant.csvの中身です(画像添付出来なかったのでリンクで失礼します)、
これは二回動作させて一回目をhoge、二回目をhogehogeにした結果です。
画像

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+2

初めて名前が出てきたレストランはしっかりとcsvに記録がされるのですが、
二回目以降名前が出てきたレストラン名に関しては上手く"Count"キーがカウントアップされません、
何故でしょうか。

if (restaurant in row) == True:
    print(int(row[1]) + 1)
    row[1] = int(row[1]) + 1
    print("Restaurant is Exist")
    restaurant_is_exist = True

変数rowはあくまでもcsvから読み取った結果であって、
書き換えれば自動的にcsvファイルが更新されるわけではありません。

手動で当該行を書き直してやる必要があります。


プログラム冒頭でcsvファイルを全て読み込み、
データを更新した後、プログラム終了直前に再度書き出すのが楽なように思います。

この場合ファイルが既に存在するかに依って書き出しモードを変える必要もありません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/11 14:29 編集

    回答を頂きありがとうございます。
    データベース上でやっているわけでは無いので、
    csv上に上書きしなければならなく出来なかったとは私の勉強不足でした。

    重ね重ね質問になってしまい申し訳ないのですが2つほどお聞きしたいことがあります。

    ①手動で当該行を書き直しすにはどの様な方法があるのでしょうか。appendなどを用いれば出来るのでしょうか。

    ➁「プログラム冒頭でcsvファイルを全て読み込み、
    データを更新した後、プログラム終了直前に再度書き出すのが楽なように思います。」
    とは、csvを全て読み込んだ後、レストラン名を追加 or カウントアップを行ってから全文csvに上書きということでしょうか。

    お手数をおかけしますが、
    お暇な時で良いのでよろしくお願いいたします。

    キャンセル

  • 2018/10/11 14:32

    ①開いているファイルをそのまま編集する方法もありますが、大抵コードが難解になるので完全に作り直す方が楽です。

    ②概ね、はい。上書きというか同名ファイルの作り直しですね。

    キャンセル

checkベストアンサー

+1

カウントアップされないのは、前回までの結果を読み込んでいないのが原因のため、以下のようにしてみてはどうでしょうか。

 サンプルコード

import csv
import os

data = {}

# ファイルが存在すれば、読み込む。
if os.path.exists('data.csv'):
    with open('data.csv', encoding='utf-8') as f:
        data = {name: int(count) for name, count in list(csv.reader(f))}

print('#####################################################')
print('どこのレストランが好きですか?')
print('#####################################################')
name = input()

# 存在する場合はカウントアップ、そうでない場合はキー追加
if name in data:
    data[name] += 1
else:
    data[name] = 1

# ファイルに書き込む。
with open('data.csv', 'w', encoding='utf-8') as f:
    writer = csv.writer(f)
    for name, count in data.items():
        writer.writerow([name, count])

 実行例

ロイヤルホスト,2
マクドナルド,1
ジョナサン,2

入力

#####################################################
どこのレストランが好きですか?
#####################################################
はなまるうどん
はなまるうどん,1
ロイヤルホスト,2
マクドナルド,1
ジョナサン,2

 追記

# list(reader) は [row for row in reader] と同じ
lst = list(reader)
print(lst)
# [['はなまるうどん', '1'], ['ロイヤルホスト', '3'], ['マクドナルド', '1'], ['ジョナサン', '2']]
for name, count in lst:
    print(name, count)
# はなまるうどん 1
# ロイヤルホスト 3
# マクドナルド 1
# ジョナサン 2

lst を dict の内包表現 を使って dict にしています。

dic = {i: i * 2 for i in range(5)}
print(dic)  # {0: 0, 1: 2, 2: 4, 3: 6, 4: 8}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/11 16:14

    詳しく追記して頂きありがとうございます。
    どの様に動いているのかある程度理解できるようになりました。

    三度失礼なのですが、1つ問題が発生しまして、
    先ほどの教えて頂いたコードを1回目実行するのは問題なく動いたのですが、
    2回目の実行の時に以下の様なエラーが出てしまいました。

    Traceback (most recent call last):
    File "C:/Users/〇〇〇/PycharmProjects/python_programming/practice01-kai.py", line 9, in <module>
    data = {name: int(count) for name, count in list(csv.reader(f))}
    File "C:/Users/〇〇〇/PycharmProjects/python_programming/practice01-kai.py", line 9, in <dictcomp>
    data = {name: int(count) for name, count in list(csv.reader(f))}
    ValueError: not enough values to unpack (expected 2, got 0)
    ※〇は伏字

    これは値が足りていないエラーなのは理解できましたが、
    どの様に解決すればよろしいのでしょうか。

    キャンセル

  • 2018/10/11 16:27

    csv の各列は `レストラン名,数` となっていることを想定しています。
    編集されたりして空行が入ってしまったのかもしれません。
    ```
    data = {row[0]: int(row[1]) for row in list(csv.reader(f)) if row}
    ```
    に書き換えてみてはどうでしょうか。if row で row が空文字の場合は無視するようにします。

    キャンセル

  • 2018/10/11 16:39

    書き換えたら出来ました、ありがとうございます。
    他にも下記の一行に、
    ```
    with open('data.csv', 'w', encoding='utf-8') as f:
    ```
    newline=''を付け加えても改行が取り払われて出来ました。
    ```
    with open('data.csv', 'w', encoding='utf-8', newline='') as f:
    ```

    色々とお手数をおかけしまして申し訳ありません、
    ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる