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

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

ただいまの
回答率

89.10%

Python 問題が理解できない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 236

Tohmas_1010

score 13

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

[8, 11, 11, 4]
[10, 11, 11, 4]
[10, 8, 4]
[10, 8, 4]
[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つ含む。

def check_hand(a,b,c,d,e):
    list_hands = [a,b,c,d,e]
    dict_hands = {0 : "NO PAIR", 1 : "ONE PAIR", 2 : "TWO PAIR", 3 : "THREE CARD", 4 : "FOUR CARD", 5 : "FULL HOUSE"}
    results = []

    for i in list_hands:#カードXを選ぶ
        count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント

        left_hands = [n for n in list_hands  if n  != i] #Xの数字を除いた残りの手札
        for j in left_hands:#X以外の数字のカードからカードYを選ぶ
            count_j = list_hands.count(j)#手札の中にあるカードYの個数をカウント
            if count_i == 2 and count_j < 2:
                results.append(1)
            elif count_i == 2 and count_j == 2:
                results.append(2)
            elif count_i == 3 and count_j == 1:
                results.append(3)
            elif count_i == 4 and count_j == 1 :
                results.append(4)
            elif count_i == 3 and count_j == 2 :
                results.append(5)
            else:
                results.append(0)
    result = max(results)
    return dict_hands[result]

print(check_hand(10,8,11,11,4)) 
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

元の回答

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

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

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

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

実験

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

def check_hand(a,b,c,d,e):
    list_hands = [a,b,c,d,e]
    dict_hands = {0 : "NO PAIR", 1 : "ONE PAIR", 2 : "TWO PAIR", 3 : "THREE CARD", 4 : "FOUR CARD", 5 : "FULL HOUSE"}
    results = []

    for i in list_hands:#カードXを選ぶ
        count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント

        # left_hands = [n for n in list_hands  if n  != i] #Xの数字を除いた残りの手札
        left_hands = []
        for n in list_hands:
            # ↓ この時点での n, i の値を確認します
            print('n, i = ' + str(n) + ', ' + str(i))
            if n  != i:
                left_hands.append(n)
        # ↓ left_hands の値を確認します
        print('left_hands = ' + str(left_hands))
        print('---------------------------------')
        for j in left_hands:#X以外の数字のカードからカードYを選ぶ
            count_j = list_hands.count(j)#手札の中にあるカードYの個数をカウント
            if count_i == 2 and count_j < 2:
                results.append(1)
            elif count_i == 2 and count_j == 2:
                results.append(2)
            elif count_i == 3 and count_j == 1:
                results.append(3)
            elif count_i == 4 and count_j == 1 :
                results.append(4)
            elif count_i == 3 and count_j == 2 :
                results.append(5)
            else:
                results.append(0)
    result = max(results)
    return dict_hands[result]

print(check_hand(10,8,11,11,4))

実行結果:

$ python test.py
n, i = 10, 10
n, i = 8, 10
n, i = 11, 10
n, i = 11, 10
n, i = 4, 10
left_hands = [8, 11, 11, 4]
---------------------------------
n, i = 10, 8
n, i = 8, 8
n, i = 11, 8
n, i = 11, 8
n, i = 4, 8
left_hands = [10, 11, 11, 4]
---------------------------------
n, i = 10, 11
n, i = 8, 11
n, i = 11, 11
n, i = 11, 11
n, i = 4, 11
left_hands = [10, 8, 4]
---------------------------------
n, i = 10, 11
n, i = 8, 11
n, i = 11, 11
n, i = 11, 11
n, i = 4, 11
left_hands = [10, 8, 4]
---------------------------------
n, i = 10, 4
n, i = 8, 4
n, i = 11, 4
n, i = 11, 4
n, i = 4, 4
left_hands = [10, 8, 11, 11]
---------------------------------
ONE 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_icount_j を使って、
次の ifelifelse ブロックで役の判定を行っています:

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

残りの手札を作る理由

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

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

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

実験

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

def check_hand(a,b,c,d,e):
    list_hands = [a,b,c,d,e]
    dict_hands = {0 : "NO PAIR", 1 : "ONE PAIR", 2 : "TWO PAIR", 3 : "THREE CARD", 4 : "FOUR CARD", 5 : "FULL HOUSE"}
    results = []

    for i in list_hands:#カードXを選ぶ
        count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント

        # left_hands = [n for n in list_hands  if n  != i] #Xの数字を除いた残りの手札
        # left_hands = []
        # for n in list_hands:
        #     # ↓ この時点での n, i の値を確認します
        #     print('n, i = ' + str(n) + ', ' + str(i))
        #     if n  != i:
        #         left_hands.append(n)
        # # ↓ left_hands の値を確認します
        # print('left_hands = ' + str(left_hands))
        # print('---------------------------------')
        # for j in left_hands:#X以外の数字のカードからカードYを選ぶ
        for j in list_hands:#X以外の数字のカードからカードYを選ぶ
            count_j = list_hands.count(j)#手札の中にあるカードYの個数をカウント
            print("カードX, Y = " + str(i) + ", " + str(j))
            print("個数  X, Y = " + str(count_i) + ", " + str(count_j))
            if count_i == 2 and count_j < 2:
                print("ONE PAIR")
                results.append(1)
            elif count_i == 2 and count_j == 2:
                print("TWO PAIR")
                results.append(2)
            elif count_i == 3 and count_j == 1:
                print("THREE CARD")
                results.append(3)
            elif count_i == 4 and count_j == 1 :
                print("FOUR CARD")
                results.append(4)
            elif count_i == 3 and count_j == 2 :
                print("FULL HOUSE")
                results.append(5)
            else:
                print("NO PAIR")
                results.append(0)
            print('---------------------------------')
    result = max(results)
    return dict_hands[result]

print(check_hand(10,8,11,11,4))

実行結果:

$ python test.py
カードX, Y = 10, 10
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 10, 8
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 10, 11
個数  X, Y = 1, 2
NO PAIR
---------------------------------
カードX, Y = 10, 11
個数  X, Y = 1, 2
NO PAIR
---------------------------------
カードX, Y = 10, 4
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 8, 10
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 8, 8
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 8, 11
個数  X, Y = 1, 2
NO PAIR
---------------------------------
カードX, Y = 8, 11
個数  X, Y = 1, 2
NO PAIR
---------------------------------
カードX, Y = 8, 4
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 11, 10
個数  X, Y = 2, 1
ONE PAIR
---------------------------------
カードX, Y = 11, 8
個数  X, Y = 2, 1
ONE PAIR
---------------------------------
カードX, Y = 11, 11
個数  X, Y = 2, 2
TWO PAIR
---------------------------------
カードX, Y = 11, 11
個数  X, Y = 2, 2
TWO PAIR
---------------------------------
カードX, Y = 11, 4
個数  X, Y = 2, 1
ONE PAIR
---------------------------------
カードX, Y = 11, 10
個数  X, Y = 2, 1
ONE PAIR
---------------------------------
カードX, Y = 11, 8
個数  X, Y = 2, 1
ONE PAIR
---------------------------------
カードX, Y = 11, 11
個数  X, Y = 2, 2
TWO PAIR
---------------------------------
カードX, Y = 11, 11
個数  X, Y = 2, 2
TWO PAIR
---------------------------------
カードX, Y = 11, 4
個数  X, Y = 2, 1
ONE PAIR
---------------------------------
カードX, Y = 4, 10
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 4, 8
個数  X, Y = 1, 1
NO PAIR
---------------------------------
カードX, Y = 4, 11
個数  X, Y = 1, 2
NO PAIR
---------------------------------
カードX, Y = 4, 11
個数  X, Y = 1, 2
NO PAIR
---------------------------------
カードX, Y = 4, 4
個数  X, Y = 1, 1
NO PAIR
---------------------------------
TWO PAIR

count_i と count_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_i と count_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 となります

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

result = max(results)

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/05 13:14 編集

    変な書き方でしたね、、、
    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が、なぜ上記のような増え方をするのか分かりません。

    キャンセル

  • 2020/07/05 13: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 回表示されます

    キャンセル

  • 2020/07/05 13:40

    お陰様で理解できました!

    とても丁寧にご教授くださりありがとうございましたm(__)m

    キャンセル

0

    for i in list_hands:#カードXを選ぶ
        count_i = list_hands.count(i)#手札の中にあるカードXの個数をカウント

        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/05 13:41

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

    キャンセル

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

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