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

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

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

565閲覧

Python 問題が理解できない

Tohmas_1010

総合スコア15

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

1クリップ

投稿2020/07/01 06:27

編集2020/07/01 06:29

下にあるPythonコードの9行目の、#Xの数字を除いた残りの手札 が理解できません。
if n != i のnとiは全て同じ10,8,11,11,4なので、すべてはじかれて[]空のリストができあがると思ったんですけど、print(left_hands)してみた結果、

python

1[8, 11, 11, 4] 2[10, 11, 11, 4] 3[10, 8, 4] 4[10, 8, 4] 5[10, 8, 11, 11]

このように出力されました。
なぜこのような処理をする必要があるのか、どうしてこうなったのかが分かりません。
どなたかご教授いただけると幸いです。

【問題のリンク https://yukicoder.me/problems/no/227】
問題:
5枚のカードが配られます。
それぞれのカードには、1以上13以下のいずれかの整数が書かれています。
カードに書かれている整数の組み合わせによって役が決まります。

配られた5枚のカードが、以下のいずれの役に該当するかを調べてください。複数の役に該当する場合は、以下で先に記述した方の役に該当するものとします。

条件:
FULL HOUSE
ある数をちょうど3つと、別の数をちょうど2つ含む。
FOUR CARD
ある数をちょうど4つ含む
THREE CARD
ある数をちょうど3つ含む。
TWO PAIR
ある数をちょうど2つと、別の数をちょうど2つ含む。
ONE PAIR
ある数をちょうど2つ含む。

python

1def check_hand(a,b,c,d,e): 2 list_hands = [a,b,c,d,e] 3 dict_hands = {0 : "NO PAIR", 1 : "ONE PAIR", 2 : "TWO PAIR", 3 : "THREE CARD", 4 : "FOUR CARD", 5 : "FULL HOUSE"} 4 results = [] 5 6 for i in list_hands:#カードXを選ぶ 7 count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント 8 9 left_hands = [n for n in list_hands if n != i] #Xの数字を除いた残りの手札 10 for j in left_hands:#X以外の数字のカードからカードYを選ぶ 11 count_j = list_hands.count(j)#手札の中にあるカードYの個数をカウント 12 if count_i == 2 and count_j < 2: 13 results.append(1) 14 elif count_i == 2 and count_j == 2: 15 results.append(2) 16 elif count_i == 3 and count_j == 1: 17 results.append(3) 18 elif count_i == 4 and count_j == 1 : 19 results.append(4) 20 elif count_i == 3 and count_j == 2 : 21 results.append(5) 22 else: 23 results.append(0) 24 result = max(results) 25 return dict_hands[result] 26 27print(check_hand(10,8,11,11,4))

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

元の回答

python

1 left_hands = [n for n in list_hands if n != i] #Xの数字を除いた残りの手札

この内包表記内では n には list_hands の要素が順に割り当てられますが、
i の値は変化しません

上記の内包表記は、
次の forif のブロックで構成されたコードと同様の処理を行います:

python

1 left_hands = [] 2 for n in list_hands: 3 if n != i: 4 left_hands.append(n)

実験

変数の変化を確認するために、内包表記を forif のブロックに書き換えて
print() を追加してみましょう:

python

1def check_hand(a,b,c,d,e): 2 list_hands = [a,b,c,d,e] 3 dict_hands = {0 : "NO PAIR", 1 : "ONE PAIR", 2 : "TWO PAIR", 3 : "THREE CARD", 4 : "FOUR CARD", 5 : "FULL HOUSE"} 4 results = [] 5 6 for i in list_hands:#カードXを選ぶ 7 count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント 8 9 # left_hands = [n for n in list_hands if n != i] #Xの数字を除いた残りの手札 10 left_hands = [] 11 for n in list_hands: 12 # ↓ この時点での n, i の値を確認します 13 print('n, i = ' + str(n) + ', ' + str(i)) 14 if n != i: 15 left_hands.append(n) 16 # ↓ left_hands の値を確認します 17 print('left_hands = ' + str(left_hands)) 18 print('---------------------------------') 19 for j in left_hands:#X以外の数字のカードからカードYを選ぶ 20 count_j = list_hands.count(j)#手札の中にあるカードYの個数をカウント 21 if count_i == 2 and count_j < 2: 22 results.append(1) 23 elif count_i == 2 and count_j == 2: 24 results.append(2) 25 elif count_i == 3 and count_j == 1: 26 results.append(3) 27 elif count_i == 4 and count_j == 1 : 28 results.append(4) 29 elif count_i == 3 and count_j == 2 : 30 results.append(5) 31 else: 32 results.append(0) 33 result = max(results) 34 return dict_hands[result] 35 36print(check_hand(10,8,11,11,4))

実行結果:

console

1$ python test.py 2n, i = 10, 10 3n, i = 8, 10 4n, i = 11, 10 5n, i = 11, 10 6n, i = 4, 10 7left_hands = [8, 11, 11, 4] 8--------------------------------- 9n, i = 10, 8 10n, i = 8, 8 11n, i = 11, 8 12n, i = 11, 8 13n, i = 4, 8 14left_hands = [10, 11, 11, 4] 15--------------------------------- 16n, i = 10, 11 17n, i = 8, 11 18n, i = 11, 11 19n, i = 11, 11 20n, i = 4, 11 21left_hands = [10, 8, 4] 22--------------------------------- 23n, i = 10, 11 24n, i = 8, 11 25n, i = 11, 11 26n, i = 11, 11 27n, i = 4, 11 28left_hands = [10, 8, 4] 29--------------------------------- 30n, i = 10, 4 31n, i = 8, 4 32n, i = 11, 4 33n, i = 11, 4 34n, i = 4, 4 35left_hands = [10, 8, 11, 11] 36--------------------------------- 37ONE PAIR

追記

count_j が必要な理由

その次にleft_handsの4個のリストをforで回してjにいれて、
list_handsの値(10,8,11,11,4)にjがいくつ含まれているのかカウントしていますが、
なぜcount_jが必要なのでしょうか??
3週目の11の場合、
list_handsにjの値がいくつあるかカウントして、
1,2,2,1,1,2,2~がcount_jに代入される→

別の数をちょうど 2 つ含」んでいないかを調べるためです

この問題は次のことを求めています:

配られた5枚のカードが、以下のいずれの役に該当するかを調べてください。

役名条件
FULL HOUSEある数をちょうど 3 つと、別の数をちょうど 2 つ含む
FOUR CARDある数をちょうど 4 つ含む
THREE CARDある数をちょうど 3 つ含む
TWO PAIRある数をちょうど 2 つと、別の数をちょうど 2 つ含む
ONE PAIRある数をちょうど 2 つ含む

この Python コードでは、
ある数をいくつ含むかを調べて count_i に代入したあと、
別の数をいくつ含むかを調べて count_j に代入しています

そして、その count_i, count_j を使って、
次の if, elif, else ブロックで役の判定を行っています:

python

1 if count_i == 2 and count_j < 2: 2 results.append(1) # ONE PAIR 3 elif count_i == 2 and count_j == 2: 4 results.append(2) # TWO PAIR 5 elif count_i == 3 and count_j == 1: 6 results.append(3) # THREE CARD 7 elif count_i == 4 and count_j == 1: 8 results.append(4) # FOUR CARD 9 elif count_i == 3 and count_j == 2: 10 results.append(5) # FULL HOUSE 11 else: 12 results.append(0) # NO PAIR

残りの手札を作る理由

なぜ カード X の数字を除いた残りの手札、を作る必要があるのでしょうか?

もし、別の数をいくつ含む処理の前に
カード X の数字を除いた残りの手札を作らなければ、
カード Y を選ぶときに
カード X と同じ数字を選んでしまう可能性があります
すると、たとえば ONE PAIR でも TWO PAIR と判定されてしまいます

例では 5 枚のカードとして 10 8 11 11 4 が与えられています
ここで、カード Xカード Y11 を選んでしまうと
11 の枚数は 2 枚なので判定が TWO PAIR になってしまいます

実験

list_hands ではなく left_hands からカード Y を選ぶとどうなるか見てみましょう:

python

1def check_hand(a,b,c,d,e): 2 list_hands = [a,b,c,d,e] 3 dict_hands = {0 : "NO PAIR", 1 : "ONE PAIR", 2 : "TWO PAIR", 3 : "THREE CARD", 4 : "FOUR CARD", 5 : "FULL HOUSE"} 4 results = [] 5 6 for i in list_hands:#カードXを選ぶ 7 count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント 8 9 # left_hands = [n for n in list_hands if n != i] #Xの数字を除いた残りの手札 10 # left_hands = [] 11 # for n in list_hands: 12 # # ↓ この時点での n, i の値を確認します 13 # print('n, i = ' + str(n) + ', ' + str(i)) 14 # if n != i: 15 # left_hands.append(n) 16 # # ↓ left_hands の値を確認します 17 # print('left_hands = ' + str(left_hands)) 18 # print('---------------------------------') 19 # for j in left_hands:#X以外の数字のカードからカードYを選ぶ 20 for j in list_hands:#X以外の数字のカードからカードYを選ぶ 21 count_j = list_hands.count(j)#手札の中にあるカードYの個数をカウント 22 print("カードX, Y = " + str(i) + ", " + str(j)) 23 print("個数 X, Y = " + str(count_i) + ", " + str(count_j)) 24 if count_i == 2 and count_j < 2: 25 print("ONE PAIR") 26 results.append(1) 27 elif count_i == 2 and count_j == 2: 28 print("TWO PAIR") 29 results.append(2) 30 elif count_i == 3 and count_j == 1: 31 print("THREE CARD") 32 results.append(3) 33 elif count_i == 4 and count_j == 1 : 34 print("FOUR CARD") 35 results.append(4) 36 elif count_i == 3 and count_j == 2 : 37 print("FULL HOUSE") 38 results.append(5) 39 else: 40 print("NO PAIR") 41 results.append(0) 42 print('---------------------------------') 43 result = max(results) 44 return dict_hands[result] 45 46print(check_hand(10,8,11,11,4))

実行結果:

console

1$ python test.py 2カードX, Y = 10, 10 3個数 X, Y = 1, 1 4NO PAIR 5--------------------------------- 6カードX, Y = 10, 8 7個数 X, Y = 1, 1 8NO PAIR 9--------------------------------- 10カードX, Y = 10, 11 11個数 X, Y = 1, 2 12NO PAIR 13--------------------------------- 14カードX, Y = 10, 11 15個数 X, Y = 1, 2 16NO PAIR 17--------------------------------- 18カードX, Y = 10, 4 19個数 X, Y = 1, 1 20NO PAIR 21--------------------------------- 22カードX, Y = 8, 10 23個数 X, Y = 1, 1 24NO PAIR 25--------------------------------- 26カードX, Y = 8, 8 27個数 X, Y = 1, 1 28NO PAIR 29--------------------------------- 30カードX, Y = 8, 11 31個数 X, Y = 1, 2 32NO PAIR 33--------------------------------- 34カードX, Y = 8, 11 35個数 X, Y = 1, 2 36NO PAIR 37--------------------------------- 38カードX, Y = 8, 4 39個数 X, Y = 1, 1 40NO PAIR 41--------------------------------- 42カードX, Y = 11, 10 43個数 X, Y = 2, 1 44ONE PAIR 45--------------------------------- 46カードX, Y = 11, 8 47個数 X, Y = 2, 1 48ONE PAIR 49--------------------------------- 50カードX, Y = 11, 11 51個数 X, Y = 2, 2 52TWO PAIR 53--------------------------------- 54カードX, Y = 11, 11 55個数 X, Y = 2, 2 56TWO PAIR 57--------------------------------- 58カードX, Y = 11, 4 59個数 X, Y = 2, 1 60ONE PAIR 61--------------------------------- 62カードX, Y = 11, 10 63個数 X, Y = 2, 1 64ONE PAIR 65--------------------------------- 66カードX, Y = 11, 8 67個数 X, Y = 2, 1 68ONE PAIR 69--------------------------------- 70カードX, Y = 11, 11 71個数 X, Y = 2, 2 72TWO PAIR 73--------------------------------- 74カードX, Y = 11, 11 75個数 X, Y = 2, 2 76TWO PAIR 77--------------------------------- 78カードX, Y = 11, 4 79個数 X, Y = 2, 1 80ONE PAIR 81--------------------------------- 82カードX, Y = 4, 10 83個数 X, Y = 1, 1 84NO PAIR 85--------------------------------- 86カードX, Y = 4, 8 87個数 X, Y = 1, 1 88NO PAIR 89--------------------------------- 90カードX, Y = 4, 11 91個数 X, Y = 1, 2 92NO PAIR 93--------------------------------- 94カードX, Y = 4, 11 95個数 X, Y = 1, 2 96NO PAIR 97--------------------------------- 98カードX, Y = 4, 4 99個数 X, Y = 1, 1 100NO PAIR 101--------------------------------- 102TWO PAIR

count_icount_j による役の評価について

なぜXの数字を除いた手札×4を作ることによって、
カードXでペアになっていたもの(11,11)を除けるのでしょうか?

-(10,8,11,11,4)の場合-
count_i = 1,1,2,2,1
count_j = 1,2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,2,2

if count_i ==2 and count_j < 2
この役はワンペアですが、
count_j == 2となるのでツーペアになると思ったのですが、
なぜcount_j < 2となるのでしょうか?

上記 [残りの手札を作る理由] [検証] の実行結果で見たように、
役の判定において count_icount_j
別々の統計が評価されている」のではなく、
組み合わせごとに評価されています」

-(10,8,11,11,4)の場合-
count_i = 1,1,2,2,1
count_j = 1,2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,2,2

この、別々の統計を取るような認識が正しくありません、
次のように組み合わせでとらえる必要があります:

-(10,8,11,11,4)の場合-

count_i|count_j|役
---|---
1|1|NO PAIR
1|1|NO PAIR
1|2|NO PAIR
1|2|NO PAIR
1|1|NO PAIR
1|1|NO PAIR
1|1|NO PAIR
1|2|NO PAIR
1|2|NO PAIR
1|1|NO PAIR
2|1|ONE PAIR
2|1|ONE PAIR
2|2|TWO PAIR
2|2|TWO PAIR
2|1|ONE PAIR
2|1|ONE PAIR
2|1|ONE PAIR
2|2|TWO PAIR
2|2|TWO PAIR
2|1|ONE PAIR
1|1|NO PAIR
1|1|NO PAIR
1|2|NO PAIR
1|2|NO PAIR
1|1|NO PAIR

最後に最大の役を調べると、TWO PAIR となります

最大の役を調べているコードは次の箇所です:

python

1result = max(results)

投稿2020/07/01 07:00

編集2020/07/02 09:29
y_shinoda

総合スコア3272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tohmas_1010

2020/07/01 08:20

理解できました! iの値はnの値を全て比較するまで変わらないんですね◎ その次にleft_handsの4個のリストをforで回してjにいれて、list_handsの値(10,8,11,11,4)にjがいくつ含まれているのかカウントしていますが、なぜcount_jが必要なのでしょうか?? 3週目の11の場合、list_handsにjの値がいくつあるかカウントして、1,2,2,1,1,2,2~がcount_jに代入される→
y_shinoda

2020/07/01 08:57

回答に追記してみました、 さらにわからなければ遠慮なく追加でご質問どうぞ!
Tohmas_1010

2020/07/02 05:16

ありがとうございます! 考えても分からなかったので質問させていただきますm(__)m その一個前なのですが、なぜ#Xの数字を除いた残りの手札、を作る必要があるのでしょうか?
Tohmas_1010

2020/07/02 05:37

どこかで変な解釈をしてるかもです。。。
y_shinoda

2020/07/02 06:10

「残りの手札を作る理由」を追記しました、ご確認お願いします!
Tohmas_1010

2020/07/02 08:09 編集

ありがとうございますm(__)m Xの数字を除いた手札を作ることによって、count_iの時に揃った数字とは別で揃っている数字(ツーペアの場合など)を調べることが可能になるという解釈で間違えないでしょうか? count_jではcount_iの時に揃った数字(11,11)を除いたカードYの個数をカウントしているということですよね? 何か抜けていればご指摘してくれると嬉しいです。
y_shinoda

2020/07/02 08:06

そのとおりです!
Tohmas_1010

2020/07/02 08:46 編集

なぜXの数字を除いた手札×4を作ることによって、カードXでペアになっていたもの(11,11)を除けるのでしょうか? -(10,8,11,11,4)の場合- count_i = 1,1,2,2,1 count_j = 1,2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,2,2 if count_i == 2 and count_j < 2: #ワンペア if count_i ==2 and count_j == 2: #ツーペア 二つとも試してみた結果両方Trueになります...
y_shinoda

2020/07/02 09:22

追記しました、ご確認おねがいします!
Tohmas_1010

2020/07/04 03:49

遅くなり申し訳ありませんm(__)m ”””count_i = [1,1,2,2,1]、count_j = [1,2,2,1,1,2,2,1,1,1,1] count_iの0番目の1と、count_jの0~3番目の1,2,2,1 count_iの1番目の1と、count_jの4~7番目の1,2,2,1 count_iの2番目の2と、count_jの8~10番目の1,1,1””” count_iの0番目の固定した1に対して、count_jの0~3番目の1,2,2,1の組み合わせを調べる。というように、なぜcount_iだけが固定されるのかが分かりません。。。 left_hands = [n for n in list_hands if n != i] これも同様に、iは固定されているというのはy_shinodaさんからの回答で分かったのですが、なぜ、どのような条件が揃ったときに固定されるのかが分かりません。 時間を取らせてしまい申し訳ありませんm(__)m
y_shinoda

2020/07/04 04:02

回答の前に、こちらで一旦質問させてください、 なぜ count_i は固定されないと思いますか? count_i が固定されるのがわからないということは、 「count_i が固定されないはずだ」と思う理由があると思うのですが、 それを教えていただけると、その点について解説することで より理解につながる回答をお伝えできると思います
Tohmas_1010

2020/07/05 03:10 編集

count_iの0番目とcount_jの0~3番目 count_iの1番目とcount_jの4~7番目 という処理になるというのは分かっているのですが。 count_iの0番目とcount_jの0番目 count_iの1番目とcount_jの1番目 count_iの2番目とcount_jの2番目 count_iの最後の4番目が終わったら、また0番目に戻る。 と考えてしまい、count_iが固定される理由が見つかりません。。。
Tohmas_1010

2020/07/05 04:01 編集

"for j in left_hands:"以降のブロックのif文でcount_iとcount_jが評価されているので、 count_i = 1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1 count_j = 1,2,2,1,1,2,2,1,1,1,1,1,1,1,1,1,2,2 このようにcount_i = 1,1,2,2,1が最後のfor文で回した数に応じて増えていることを忘れていました! 固定の疑問については解決しましたm(__)m でも、count_iがなぜこのような増え方(1*8, 2*6, 1*4)をするのかがわかりません。
y_shinoda

2020/07/05 04:07

> count_iがなぜこのような増え方(1*8, 2*6, 1*4)をするのかがわかりません。 の 8, 6, 4 は何の値を示していますか?
Tohmas_1010

2020/07/05 04:22 編集

変な書き方でしたね、、、 count_i = 1,1,1,1,1,1,1,1,2,2,2,2,2,2,1,1,1,1 こちらです◎ count_i = 1,1,2,2,1が、なぜ上記のような増え方をするのか分かりません。
y_shinoda

2020/07/05 04:24

for j in left_hands: このループの繰り返し回数は left_hands の要素数次第です left_hands の要素数は質問欄に「print(left_hands)してみた結果」が記載されています この要素数は順に4, 4, 3, 3, 4 です なので、"1" が 4 + 4 回、 "2" が 3 + 3 回, "1" が 4 回表示されます
Tohmas_1010

2020/07/05 04:40

お陰様で理解できました! とても丁寧にご教授くださりありがとうございましたm(__)m
guest

0

python3

1 for i in list_hands:#カードXを選ぶ 2 count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント 3 4 left_hands = [n for n in list_hands if n != i] #Xの数字を除いた残りの手札

たとえば3周目、つまりiが11のとき、
if n!=i というのは、11以外のnでTrueを返します。
すなわち11をすべて抜いた手札でリストを再構成してleft_handsとするので、
[10, 8, 4]となります。

このような処理をすることで、
手札から1枚ずつ数字(X)を選んで、それが1枚きりか複数枚あるのか(=役になるのか)ということを判定しつつ、そのXたちを抜いた残りのカードについても同じこと(Yの枚数判定)を行っています。

投稿2020/07/01 06:46

jeanbiego

総合スコア3966

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Tohmas_1010

2020/07/05 04:41

この度はご教授くださりありがとうございましたm(__)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問