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

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

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

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

Q&A

解決済

7回答

189閲覧

もっと簡潔に書きたいpython3<no.1>

hmori

総合スコア12

Python 3.x

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

1グッド

0クリップ

投稿2018/05/25 22:25

前提・実現したいこと<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
を使用して書いています
以上、よろしくお願いします

tachikoma👍を押しています

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

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

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

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

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

guest

回答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

katoy

総合スコア22324

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

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

hmori

2018/05/26 14:12

ありがとうございます 読んでこういう風にかけたらいいなと思いました 読むことはできるけど自分で作り出すのが難しいです 大変助かりました
guest

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
umyu

総合スコア5846

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

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

hmori

2018/05/26 14:26

回答ありがとうございます Counterを使っているのですね すっきりしてみやすいです 大変助かりました
guest

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

hayataka2049

総合スコア30933

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

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

hmori

2018/05/26 17:22

ご回答ありがとうございます 読みやすいコード助かります 大変参考になりました
guest

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

katoy

総合スコア22324

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

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

hmori

2018/05/26 14:35

ご回答ありがとうございます groupby をまだ使ったことがないので リファレンスを読みながらコードを ありがたく拝見させていただきます 助かりました
guest

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

LouiS0616

総合スコア35658

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

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

hmori

2018/05/26 14:40

ご回答ありがとうございます 大変参考になりました 助かりました
guest

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

KSwordOfHaste

総合スコア18392

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

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

hmori

2018/05/26 14:47

ご回答ありがとうございました dictがまだ使い慣れていませんが、自分で色々書いて 慣れていきたいと思います 大変参考になりました
guest

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

tachikoma

総合スコア3601

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

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

hmori

2018/05/26 14:21

回答ありがとうございます クラスを使ってシンプルにするという方法もありですね まだクラスについても作りなれていないので 是非参考にさせていただきます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問