前提・実現したいこと<no.1>
簡潔にもっと綺麗に作りたい
よろしければご指導してください
python3 で最近プログラミングを勉強しています
標準入力で
最初に投げた回数(N)
例1 として5回
ball ⇒ ball!
ball ⇒ ball!
strike ⇒ ball!
strike ⇒ ball!
(strike) ⇒ out!
のような動きにしています
例2
最初に投げた回数(N)
例2 として4回
ball ⇒ ball!
ball ⇒ ball!
strike ⇒ strike!
ball ⇒ fourball!
もっと簡潔に綺麗に作れるのではないかと思いますが
初心者の為、冗長になってしまっています
該当のソースコード
python3
1N = int(input()) 2s = 0 3b = 0 4i = 0 5 6while i <= N-1: 7 a = input() 8 if a == 'ball': 9 b = b + 1 10 if b < 4: 11 print('ball!') 12 else: 13 print('fourball!') 14 break 15 if a == 'strike': 16 s = s + 1 17 if s < 3: 18 print('strike!') 19 else: 20 print('out!') 21 break 22 i = i+1 23
補足情報(FW/ツールのバージョンなど)
ブラウザでプログラムが書けるpaiza.ioのpython3
を使用して書いています
以上、よろしくお願いします
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答7件
0
変数の数を少なくする方針で書いてみました。
python
1N = int(input()) 2records = [] 3 4for i in range(0, N): 5 records.append(input()) 6 7 if records.count("ball") == 4: 8 print("forball!") 9 break 10 elif records.count("strike") == 3: 11 print("out!") 12 break 13 else: 14 print("{}!".format(records[-1]))
質問文にある出力例とは動作は違っています。野球の投球判定のルールに基づいて書いています。
strike, ball 以外が入力されたときのことは考慮していません。
投稿2018/05/25 23:28
総合スコア22324
0
Python
1# -*- coding: utf-8 -*- 2from collections import Counter 3score = Counter() 4outs = {'strike': (3, 'out!'), 'ball': (4, 'fourball!')} 5 6for _ in range(int(input())): 7 a = input() 8 score[a] += 1 9 end_count, msg = outs[a] 10 if score[a] == end_count: 11 print(msg) 12 break 13 14 print(a + '!')
◇参考情報
0. 4.6.5. タプル型 (tuple)
0. 4.10. マッピング型 — dict
0. 8.3.2. Counter オブジェクト
投稿2018/05/26 01:31
編集2018/05/26 01:40総合スコア5846
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
質問のコードですが、それほど冗長ではありません。一度読めば理解できる、良いコードです。
複雑なテクニックを使うと、かえって可読性を損なう場合があります。それなら多少長くても、愚直に書いた方が良い場合も多いのです。
それはそれとして、小手先のテクニックで文字数を減らしてみました。でもほとんど変えていません。
python
1N = int(input()) 2s = b = 0 # 一括代入できる 3 4for _ in range(N): # whileをforに変える。ループ変数は要らないので_にしておく(pythonの慣習) 5 a = input() 6 if a == 'ball': 7 b += 1 # 加算代入演算子を使う 8 if b < 4: 9 print('ball!') 10 else: 11 print('fourball!') 12 break 13 if a == 'strike': 14 s += 1 15 if s < 3: 16 print('strike!') 17 else: 18 print('out!') 19 break
投稿2018/05/26 14:50
総合スコア30933
0
3 項演算子と、groupby を使って書いてみました。
python
1from itertools import groupby 2 3MESSAGES = { 4 "strike": "strike!", "ball": "ball!" 5 "_fb": "foreball!", "_out": "out" 6} 7N = int(input()) 8 9records = [] 10for i in range(0, N): 11 records.append(input()) 12 score = {k: len(list(g)) for k, g in groupby(sorted(records))} 13 judge = "_fb" if score.get("ball", 0) == 4 else "_out" if score.get("strike", 0) == 3 else records[-1] 14 print(MESSAGES.get(judge, "?")) 15 if judge == "_fb" or judge == "_out": 16 break
judge を求める部分は 3 項演算子でなく、メソッドとして独立させ そのなかでは case で書いたほうがよいとはおもいますが。
投稿2018/05/26 04:38
総合スコア22324
0
簡潔かは微妙ですけど、せっかく書いたので参考までに載せときます。
Python
1from enum import Enum, auto 2 3 4class JudgeForPitch(Enum): 5 STRIKE = auto() 6 BALL = auto() 7 FOUL = auto() 8 9 @classmethod 10 def get_input(cls, *, print_message): 11 while True: 12 print_message() 13 try: 14 return { 15 "strike": cls.STRIKE, 16 "ball" : cls.BALL, 17 "foul" : cls.FOUL, 18 }[input()] 19 except KeyError: 20 pass 21 22 23AtBatResult = Enum('AtBatResult', ['STRUCK_OUT', 'FOUR_BALL']) 24def turn_at_bat(): 25 jfp = JudgeForPitch 26 27 counts = { 28 jfp.STRIKE: 0, jfp.BALL: 0 29 } 30 31 while True: 32 thrown_result = jfp.get_input( 33 print_message=lambda: print('input strike, ball or foul', end=': ') 34 ) 35 if thrown_result in counts: 36 counts[thrown_result] += 1 37 elif thrown_result is jfp.FOUL: 38 counts[jfp.STRIKE] += (counts[jfp.STRIKE] < 2) 39 40 if counts[jfp.STRIKE] == 3: 41 return AtBatResult.STRUCK_OUT 42 if counts[jfp.BALL] == 4: 43 return AtBatResult.FOUR_BALL 44 45 print( 46 'BALL: {0}, STRIKE: {1}'.format( 47 counts[jfp.BALL], counts[jfp.STRIKE] 48 ) 49 ) 50 51 52if __name__ == '__main__': 53 print(turn_at_bat())
条件と異なりますが、一打席勝負にしています。ヒットや凡打は出ませんが。
いちおうファール判定、入力チェックも機能として組み込んでます。
投稿2018/05/26 03:50
総合スコア35658
0
ベストアンサー
冗長と感じる典型的な要因に「同じようなパターンが繰り返されている」というのがあると思います。
どの言語でも同じですが「同じパターンものはまとめて処理」するとスッキリすることがあります。例えばキーが0, 1, ...の情報があってそれをキーの値に応じてどれかをインクリメントするとき
python
1if key == 0: 2 v0 += 1 3elif key == 1: 4 v1 += 1 5elif ... 6 ...
こういう書き方はしたくないと感じます。プログラマーは誰もが「怠惰」なので特に同じことの繰り返しは見た瞬間「ヤダー」と感じますな。このようなパターンはキー(配列の指標もキーの一種と言えます)によって異なる値へアクセスできるlist, dict, etc.を使うのが常道の一つです。上の例でいえば
v[key] += 1
で済みますよね?これを本件に適用するなら
Python
1ball_or_strike = input() 2count[ball_or_strike] += 1
と書ければボールとストライク両方のカウントができますのでdictが便利でしょう。カウントの上限や表示するメッセージが違うという話も同じ考え方で扱うことが可能です。
リスト1
python
1count = dict(ball=0, stroke=0) 2limit = dict(ball=4, stroke=3) 3settlement = dict(ball='walk', stroke='out') 4while True: 5 bos = input() 6 if bos in count: 7 count[bos] += 1 8 finished = count[bos] >= limit[bos] 9 print(settlement[bos] if finished else bos) 10 if finished: 11 break
また上ではball, strikeごとに3つの情報を取り扱ってますがそれぞれを別々の変数にしているのが煩雑と感じることもあります。3つならまだしも4つ5つ...と増えていくと色んな変数があちこちにでてきてコードが捉えにくくなる原因になると思います。これは同じコードを複数個所に書いているかどうかという話とは別ですね。こうした場合「あるひとまとまりの情報をなにかの構造データに閉じ込める」なんてことをするとスッキリすることがあります。
リスト2
Python
1states = dict( 2 ball=dict(count=0, limit=4, settlement='walk'), 3 strike=dict(count=0, limit=3, settlement='out'), 4) 5 6while True: 7 bos = input() 8 if bos in states: 9 s = states[bos] 10 s['count'] += 1 11 finished = s['count'] >= s['limit'] 12 print(s['settlement'] if finished else bos) 13 if finished: 14 break
リスト1で出てくる変数は5, リスト2では4なのでこの例では違いは大差ないと感じられますがcount, limit, settlementといった情報が増えてくると変数の数を小さく抑える効果(情報のまとまりの捉えやすさ)が出てくると思います。
本件そのものについていえば質問者さんのコードだって充分分かり易いと思いますが、もう少し複雑なコードになっても耐えられるようなものを書く練習として、上記あるいはその他の設計・コーディングの仕方について経験を積むとよいと思います。言語機能(様々な構文, etc.)、基本的ライブラリーの機能(list, dict, etc.)などの知識をつけるのも大事ですが、結局は自分で色々書いてみるのが一番ではないでしょうか。
投稿2018/05/26 02:55
総合スコア18392
0
少し構造化してみました。while文のロジックを簡潔にするために全体としては長くなっています。
このコードの目標は次のようにwhileの中をシンプルにして、細かな判定やprint出力をBatterクラスに委譲することです。
python
1N = int(input()) 2 3batter = Batter() 4 5while True: 6 a = input() 7 try: 8 if a == 'ball': 9 batter.ball() 10 if a == 'strike': 11 batter.strike() 12 except (BatterOut, BatterFourball): 13 break
まず、三振アウトとフォアボール用の例外クラスを自作しておきます。この場合、例外クラスの名前だけが重要なので、中身はpassします。
python
1class BatterOut(Exception): 2 pass 3 4class BatterFourball(Exception): 5 pass
バッターはストライクかボールだけ実装します(残念ながらヒットを打てないバッターです)。
python
1class Batter: 2 def __init__(self): 3 self._ball = 0 4 self._strike = 0 5 6 def strike(self): 7 self._strike += 1 8 print("strike!") 9 if self._strike == 3: 10 print("out!") 11 raise BatterOut 12 13 def ball(self): 14 self._ball += 1 15 print("ball!") 16 if self._ball == 4: 17 print("fourball!") 18 raise BatterFourball
strikeとballの処理を各メソッドに委譲しているわけです。
以上をまとめると、全体のコードは次のようになります。
Python
1class BatterOut(Exception): 2 pass 3 4class BatterFourball(Exception): 5 pass 6 7class Batter: 8 def __init__(self): 9 self._ball = 0 10 self._strike = 0 11 12 def strike(self): 13 self._strike += 1 14 print("strike!") 15 if self._strike == 3: 16 print("out!") 17 raise BatterOut 18 19 def ball(self): 20 self._ball += 1 21 print("ball!") 22 if self._ball == 4: 23 print("fourball!") 24 raise BatterFourball 25 26N = int(input()) 27 28batter = Batter() 29 30while True: 31 a = input() 32 try: 33 if a == 'ball': 34 batter.ball() 35 if a == 'strike': 36 batter.strike() 37 except (BatterOut, BatterFourball): 38 break
投稿2018/05/26 00:40
総合スコア3601
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/05/26 14:12