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

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

ただいまの
回答率

87.49%

random.sampleを使っているのに要素が重複する

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,051
退会済みユーザー

退会済みユーザー

python3でクイズプログラムを作成しようとしています。
1.問題に使う植物Aをランダムに選択
2.Aと同じ科の植物の中から別のひとつBを選択(答えとなる)
3.Aと異なる科の植物の中から3つを選択(C,D,E)
4.「Aと同じ科の植物はどれか選べ」という問題に
B,C,D,Eの選択肢を提示する
というプログラムを想定しています。

上記4.の部分について、選択肢4つを格納したb_optionsに対して
random.sampleを使用しているのですが、なぜかひとつが重複してしまいます。
(4つの値のうち、3種類、うちひとつが2回表示される)
きちんと4つ出すために、何が間違っているのか教えていただけないでしょうか。

該当のソースコード

import random
import csv
import tkinter, tkinter.messagebox

# 問題のもととなるcsvファイルを読み込み
# csvは1行目に name,family,character
#      2行目に カブ,アブラナ科,春の七草
#      3行目以降 キキョウ,キキョウ科,秋の七草
# といった感じで3列の値が並ぶ

with open('plant.csv', newline='') as csvfile:
    reader = csv.DictReader(csvfile)
    rows = []
    for row in reader:
        rows.append(row)

# 上記DictReaderで読み込んだ辞書リストから、問題用に、ひとつの辞書を呼び出す
p_plant = random.choice(rows)
p_name = p_plant["name"]

# 問題用の植物と同じ科(family)の植物をリストにして、
# その中から問題用の植物を削除。
# 残りからひとつを選ぶ(=その植物が答えになる)

q_list = [x['name'] for x in rows if x['family'] == p_plant["family"]]
q_list.remove(p_plant["name"])
answer = random.choice(q_list)

# 答えとは異なる科(family)の植物をリスト化し、そこから3つ選ぶ

b_list = [x['name'] for x in rows if x['family'] != p_plant["family"]]
b_options = random.sample(b_list , 3)
b_options.append(str(answer))

tki = tkinter.Tk()
tki.geometry('300x400')
tki.title('ラジオボタン')

# ラジオボタンのラベルをリスト化する
# はずなんですが、ここがうまくいっていません・・
rdo_txt = [random.sample(b_options , k=1) , random.sample(b_options , k=1) , random.sample(b_options , k=1) ,random.sample(b_options , k=1)]
# ラジオボタンの状態
rdo_var = tkinter.IntVar()

# ラジオボタンを動的に作成して配置
for i in range(len(rdo_txt)):
    rdo = tkinter.Radiobutton(tki, value=i, variable=rdo_var, text=rdo_txt[i]) 
    rdo.place(x=50, y=30 + (i * 24))

# ボタンクリックイベント
def btn_click():
    num = rdo_var.get()

    if rdo_txt[num] == str(answer):
        tkinter.messagebox.showinfo('結果' , "正解!")
    else:
        tkinter.messagebox.showinfo("結果" , '不正解!正解は' + answer)

# ボタン作成 
btn = tkinter.Button(tki, text='答え合わせ', command=btn_click)
btn.place(x=100, y=170)

var = tkinter.StringVar()
var.set(p_name + "と同じ科の植物はどれでしょう")
label = tkinter.Label(tki, textvariable=var, width=100, )
label.pack()
label.bind("<ButtonPress-1>", update_label)

tki.mainloop()
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • otn

    2020/01/20 22:52

    質問文が異様に見にくいと思いませんか?

    キャンセル

  • hayataka2049

    2020/01/20 22:52

    質問を編集し、コードを

    ```python
    コード
    ```

    のようにmarkdownでくくるようにしてください。現状だと不格好だしインデントが潰れます。

    キャンセル

回答 1

checkベストアンサー

0

4個から3個を重複なしで抽出する

import random

samples = ['A', 'B', 'C', 'D']
print(random.sample(samples, 3))
#['D', 'B', 'C']

【NG例】
4個から1個を抽出 × 3回 ⇒ 重複することもしないこともある

import random
samples = ['A', 'B', 'C', 'D']
print(random.sample(samples, 1), random.sample(samples, 1), random.sample(samples, 1))
#['B', 'D', 'B']

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/01/20 22:49

    ありがとうございます。
    しかしこのプログラムで
    rdo_txt = [random.sample(b_options , k=4)]
    としてしまうと、4つの要素が1行で表示され、ラジオボタンが1つになってしまいます。
    重複せず、並びもランダムに、4つの選択肢として表示するにはどうすればよいでしょうか。

    キャンセル

  • 2020/01/20 22:54

    一旦リストに格納してから、1個ずつ取り出せば良いと思います。
    私のコードの例)
    temp = random.sample(samples, 3)
    for i in temp:
    print(i)
    #D
    #B
    #C

    キャンセル

  • 2020/01/20 23:14

    そもそもリスト型で返るのだから
    rdo_txt = random.sample(b_options , k=4)
    でいいし、あるいは単にrandom.shuffleを使うことも検討してください。
    (回答するほどでもないのでmeg_さんのコメント欄をお借りして書かせていただきました)

    キャンセル

  • 2020/01/20 23:25

    なるほど。ラジオボタン周りについて調べ始めたところで、rdo_txtの使い方を十分に理解できていませんでした。希望する動きが実現できました。ありがとうございました。

    キャンセル

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

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

関連した質問

同じタグがついた質問を見る