Python100本ノック(〜30本目)
「自作Python100本ノック1日目(はじめに〜5本目)」
「自作Python100本ノック2日目(6本目〜10本目)」
「自作Python100本ノック3日目(11本目〜15本目)」
「自作Python100本ノック4日目(16本目〜20本目)」
「自作Python100本ノック5日目(20本目〜25本目)」
「自作Python100本ノック6日目(26本目〜30本目)」
はじめに
今回から「自作Python100本ノック」を始めていくのですが最初に、 「なぜやるのか?」 「どういう問題を対象にしているのか?」 「どの様に進めていくか?」 を簡単に整理しておきます。
なぜやるのか
1、エンジニアのサマーインターンのコーディング試験に受かるため 今まではなんとか基礎力を隠してこれたんですが、ついに誤魔化しが効かない壁が現れました。
2、生駒ちゃんが乃木坂46を卒業し暇になったから 急に毎日が退屈で暇になってしまいました。
3、これからPythonを勉強する様な人にとってちょうど良い問題集を作るため ネットで検索すれば、Pythonの基礎的なコーディング問題はたくさんヒットしますが、 ページはバラバラ。難易度はバラバラ。「え?それいつ使うの?」という問題も多かったりと実用性もバラバラ。快適に勉強ができる環境ではないなと感じました。 そこで、それなら自分が色々なサイトを回って良いなと思ったものを寄せ集めて問題集を作れば、今度自分と同じ様な状況の人にとって役立つのではないかと思いました。 もちろん備忘録の意味もあります。
どういう問題を対象にしているのか?
問題は全て独断と偏見で選んでいますが、 実用性や応用性があるものを優先して集めるつもりです。
「最低限の知識(print,for文,if文,関数の使い方等)は勉強したから、ちょっとした問題解いてみたいな」
「CheckiOとかは難しすぎるから入門者向きのちょど良い問題ないかなあ。。。」
「解答がすぐ見れるやつが良いな。。」
という自分みたいな人が主な対象となるので、難易度もそこらへんになります。 CheckiOが1人でゴリゴリにできるという人は、クオリティ的にもCheckiOで鍛えることを強く勧めます。
どの様に進めていくか?
簡単でシンプルな問題から順に進めていきたいと思いましたが、 既に100問用意できているわけではないので、良さげな問題を見つけ次第どんどん投稿していこうと思います。 完成後余裕があれば、簡単な問題順に並び替えます。 外部から持ってきたものの出典は全て載せます。
解答は基本的に自分にとって1番わかりやすいものを載せようと思います。 「なにそのコード汚な」 「え。そんな面倒なことしてんの?それ、これ使えば1文で書けるよ。」 と思う人が多いと思いますが、 まだ自分は「コードはアートだ!」みたいな境地に辿り着いていないのでそこらへんはご了承ください。 美しい別の回答は、出典から確認してください。
作った問題集(解答がついていないバージョン)は今後まとめてGitHubに上げようと思いますので、まとめて解きたいという方はそちらを使ってください。(未定) よろしくお願いします。
自作Python100本ノック(1本〜5本目)
Q1: 1から50までの和を計算して表示
基本です。 「おいおいこのレベルでやっていくのかよ。」と思われた方もそう焦らないでください。 まだ99本ありますから。
s = 0
for i in range(1,51):
s += i
print(s)
Q2: 1000以下の素数を計算して表示せよ
素数の性質を考えれば解けますね。
for i in range(2,1001):
for n in range(2,i): #2からその数より以前の数で割り切れないものが素数となる
if i%n == 0:
break
else:
print(i)
Q3: フィボナッチ数列(10個目まで)を表示せよ
1,1,2,3,5,8・・・・・・ってなるやつです(2つ前と1つ前の数の和になる数列) こんなにシンプルに解けるとは驚きました。
a = 0
b = 1
for i in range(10):
print(b)
a, b = b, a+b
Q4: 2つの自然数の最小公倍数/最大公約数を表示せよ
2つの数字を引数に渡すと、その2つの最大公約数と最小公倍数を計算して表示してくれる関数を作ってください。 まあ、でもこれは計算方法知ってないと初見では解けないですよね。
#最大公約数
def gcd(a,b):
if b == 0:
return a
else:
return gcd(b,a%b) #この方法で最大公約数が求められます。
a = 16
b = 6
xab = gcd(a,b)
print(xab)
#最小公倍数
zab = a*b/xab #この方法で最小公倍数が求められます。
print(zab)
[出典]Pythonのお勉強 問題集
Q5: 0から100の内3の倍数と3のつく数字だけ表示せよ。
世界のナベアツさんのネタと同じ原理です。 str()
とin
を使う発想が好きです。
#最大公約数
for i in range(0,101):
if "3" in str(i) or 0 == i % 3:
print(i)
[出典]data9824さん
Q6: FizzBuzz問題
問題:1〜100までの数字のうち、3で割り切れるものは”Fizz!”,5で割り切れるものは”Buzz!”,15で割り切れるものは”FizzBuzz!”と表示させ、それ以外の数はそのままの数を表示させなさい。 みんな大好きFizzBuzz問題ですね。 なんか毎回記事の最初の問題は、簡単ですね。
for i in range(1, 101):
if i % 15 == 0:
print("Fizz Buzz!")
elif i % 3 == 0:
print("Fizz!")
elif i % 5 == 0:
print("Buzz!")
else:
print(i)
Q7: その内整数nまでの”z”の個数を計算し表示せよ(ただしif文
,for文
の使用不可)
問題:Q6と同じ規則に従って、1から整数nまでを数字,Fizz,Buzz,FizzBuzz,に分けていき、その内いくつ”z”があるか個数をカウントし表示させなさい。 条件:if文
,for文
は使用してはいけない。
if文,for文を使えば簡単ですが、それが使えないとなると頭を使いますよね。
def count_z(n):
print((n // 3 * 2) + n // 5 * 2)#「//」は割り算の整数部分の結果を出します
count_z(100)
Q8: 為替自動換算クラスの作成
問題:日本円をドルとユーロに換算するクラスを作成せよ。 条件:・1ドル=109円, 1ユーロ=129円で換算。(2018/5/8現在) ・クラスの引数に日本円を入力して、その後その値を各通貨に換算できるようする。
クラスの使い方ですね。
class YenToCurrency:
def __init__(self,yen):
self.yen = yen
def doll(self):
doll = self.yen / 109
return(doll)
def euro(self):
euro = self.yen / 129
return(euro)
exchange = YenToCurrency(3000)
print('3000円は{}ドルです。'.format(exchange.doll()))
print('3000円は{}ユーロです。'.format(exchange.euro()))
[参考]AI_STANDARD
Q9: RPGゲームクラスの作成
問題:キャラクターのステータスを登録して、お互いに攻撃することができるクラスを 作成せよ。 条件:・キャラクターは名前,体力の現在値、体力の最大値、攻撃力,防御力の 5つのパラメータをもっており、いつでも参照することができる。 ・キャラクターは別のキャラクターを攻撃して、 相手の体力を自分の攻撃力(-相手の防御力)分だけ減らすことができる。
少し長いクラスの作成となります。
class Character:
def __init__(self,name,maxhp,attack_point,defence_point):
self.name = name
self.maxhp = maxhp
self.hp = maxhp
self.attack_point = attack_point
self.defence_point = defence_point
def status(self):
return "{}:体力 {}/{}:攻撃力 {} 防御力 {}".format(self.name,self.hp,self.maxhp,self.attack_point,self.defence_point)
def attack(self,enemy):
cal_attack_point = self.attack_point - enemy.defence_point
enemy.hp -= cal_attack_point
print("{}の攻撃!{}に{}のダメージ!".format(self.name,enemy.name,cal_attack_point))
yusha = Character("勇者",60,10,2)
slime = Character("スライム",15,5,1)
# ステータスを表示
print(yusha.status())
print(slime.status())
# 勇者の攻撃
yusha.attack(slime)
# スライムの攻撃:
slime.attack(yusha)
# ステータスを表示
print(yusha.status()) # 勇者のステータス
print(slime.status()) # スライムのステータス
[参考]AI_STANDARD
Q10 Hashnumber 判定
問題:整数 X の各桁の数字の和を f(X) としたとき、 X が f(X) で割り切れる場合、X はハーシャッド数です。 整数 N が与えられるので、ハーシャッド数かどうか判定してください。
str()
や,map()
やsum()
を使う良い練習になるのではないでしょうか。
def j_hash(n):
s = str(n)
array = list(map(int, list(s)))
a = sum(array)
if n % a == 0:
print("Hashnumber")
else:
print("Not hashnumber")
j_hash(444)
[参考]やるだけPython競プロ日誌
Q11: テキストファイル内の文字をアルファベット順に表示せよ。
テキストファイルの読み込み方と、最も簡単なソートのやり方となります。
a = open("alpha.txt").read().split()
a.sort()
a
↓のように関数を作ろうとすると、None
となってしまいます。 (原因はわかりません。。どなたかわかる人いましたら教えてくださいm(._.)m) -> 解決しました。(コメント欄参照)
def sort_text(text):
text = open(text).read().split()
aws = text.sort()
print(aws)
sort_text("number.txt")
[参考]Pythonのお勉強 問題集
Q12: テキストファイル内で指定した文字がいくつ含まれているか数える
問題:テキストファイルの中に、調べたい文字がいくつ含まれているか自動で数えさせるプログラムを書きなさい。
自然言語系の処理をやる際には使えそうですよね
print(open("python.txt").read().count("by"))
↓関数を作る場合
def count_lite(text,target):
print(open(text).read().count(target))
count_lite("python.txt","by")
[出典]Pythonのお勉強 問題集
Q13: 摂氏と華氏を自動変換
問題:摂氏(℃)を入力すると華氏(°F)に変換し表示し、 華氏を入力すると摂氏に変換表示してくれる関数を作成せよ。 条件:摂氏の場合は”26C”のように入力し、華氏の場合は”67F”のように入力する。
文字列(リスト)の最後の文字をどう取ってくるか。最後以外をどう取ってくるかの練習になりますね。
def convert(text):
if text[-1] == "C":
cel = int(text[:-1])#文字列の最後の文字を取り出す
aws = cel * (9/5) + 32
elif text[-1] == "F":
fah = int(text[:-1])#文字列の最後以外の文字を取り出す
aws = (fah -32) / (9/5)
else:
aws = "正しく入力してください"
return aws
convert("45C")
[参考]Pythonのお勉強 問題集
Q14入れ子のリストを平らにする
問題:[[1,2],3,4,5,[6,[7,[8,9]]]]のように入れ子になっているリストを、 [1, 2, 3, 4, 5, 6, 7, 8, 9]のように平らに入れ直したい。
appen
とextend
の違いの勉強になります。 (詳しくはこちらを参考)
def flatten(ls):
r = []
for i in ls:
if type(i) is list:
r.extend(flatten(i))#appendではない。
else:
r.append(i)
return r
lis_a = [[1,2],3,4,5,[6,[7,[8,9]]]]
print(flatten(lis_a))
Q15: 対話型残業代自動算出システム
問題:「現在の時刻」「定時」「1時間あたりの残業代」を対話式に入力すると、 残業代が自動で表示されるシステムを作れ。 条件:時刻の入力は”17:00”のように入力される。
対話型の練習です。float
に変換しないといけないのも練習になります。
print("現在の時刻を「18:45」のように入力してください")
current_time = input(">>")
print("定時を「17:00」のように入力してください")
out_time = input(">>")
print("1時間あたりの残業代(円)を「1500」のように入力してください")
hour_money = float(input(">>"))
current_h = float(current_time[0:2])
current_m = float(current_time[3:5])
current_time_min = (60 * current_h) + current_m #分単位に統一
out_h = float(out_time[0:2])
out_m = float(out_time[3:5])
out_time_min = 60 * out_h + out_m
leave_time_min = current_time_min - out_time_min
leave_time_h = round((leave_time_min/60),2)
cal_money = leave_time_h * hour_money
print("あなたの残業時間は{0}時間です。残業代金は{1}円になります。".format(leave_time_h,cal_money))
[参考]python自習テキスト
Q16: 標準ライブラリを使ってsin60°を求める
まあ、ライブラり知ってないと解けないですよね。(こういう時に調べるという練習)
from math import sin,pi
print(sin(pi/4)) #piは180°を表す
[出典]Pythonのお勉強 問題集
Q17: 16進数ダンプ(逆バージョンも)
16進数ダンプとは、メモリーやファイルの内容などを16進数の形で目に見えるように書き出す(表示する)ことを言います。(通信用語の基礎知識より) 今回は、その16進数ダンプと、その逆の作業をライブラリを用いて実行してください。
import binascii
#文字列 -> 16進数
binascii.hexlify(b'Hello')
#16進数 -> 文字列
binascii.unhexlify('48656c6c6f')
[出典]Pythonのお勉強 問題集
Q18: パスワードを自動生成する
問題:英字(大文字小文字含める)と数字を組み合わせた、8文字のパスワードを自動で生成せよ。
#英字(小文字&大文字):string.ascii_letters
#数字:string.digits
#記号:string.punctuation
import string
import random
a = ''.join([random.choice(string.ascii_letters + string.digits) for i in range(8)]) #リストの中の文字を連結出来る
print(a)
[参考]Pythonのお勉強 問題集
Q19: ランダムな数字のリストを生成せよ
問題:表示する数字の個数、#数字の範囲(最小と最大)を指定し、その中でランダムな数字を生成
def randlist(size,lower,upper):
list = []
for i in range(size):
list.append(random.randint(lower,upper))
print(list)
randlist(10,30,90)
20: 簡単ポーカー
問題: 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:
count_i = list_hands.count(i)
for j in list_hands:
count_j = list_hands.count(j)
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]
check_hand(1,1,7,1,3)
[出典] data9824さん
Q21: 支払いパターンを計算して表示
問題:あなたは、500 円玉を A 枚、100 円玉を B 枚、50 円玉を C 枚持っています。 これらの硬貨の中から何枚かを選び、合計金額をちょうどX円にする方法は何通りありますか。 条件 Xは50の倍数である
こんなにシンプルに解けると気持ちいいですよね。
def cal_patern(a,b,c,x):
count = 0
for i in range(a + 1):
for j in range(b + 1):
for k in range(c + 1):
if 500 * i + 100 * j + 50 * k == x:
count += 1
return count
cal_patern(3,5,6,1500)
Q22: ポケットを叩くとビスケットが2倍
問題:Saraは、「ふしぎなポケット」を手に入れた。 「ふしぎなポケット」は、いくつかビスケットを入れて叩くと、入れたビスケットの数が2倍になる。 Saraは最初1枚のビスケットを持っていて、「ふしぎなポケット」を使ってちょうどN枚のビスケットにして、全部食べたいと思っている。 (食べきれないので枚数をオーバーしてはいけない) この時、ちょうどN枚にするには、Saraは最低何回ポケットを叩く必要があるか求めてください。
この手の問題はもう簡単ですね。
def pocket(aim):
count = 0
biskets = 1
while biskets < aim:
count += 1
biskets = 2 ** count
else:
print("{}回ポケットを叩いてください".format(count))
pocket(10)
[出典]yuki2006
Q23: パスワードの安全性を確認する
問題: 与えられて文字列がパスワードとして安全かどうか確認せよ。 条件:安全なパスワードとは10文字以上であり、大文字、小文字、数字が必ず1つは含まれているものとする。
いよいよChekiOの問題を解いてみます。 not and
を使い、タブーなものだけをどんどん入れていくという発想が良いですよね。
def check_pass(password):
if len(password) >= 10 and not password.isalpha() and not password.isnumeric() and not password.islower() and not password.isupper():
return True
else:
return False
print(check_pass("aiasgiHSU43"))
Q24: 文字列の内最頻な文字を表示(小文字,alphabet順)
条件:与えられる文字列に制限はないが、結果は全て小文字で表示し 1番多い頻度の文字が複数個存在する場合は、アルファベット順で早い方を表示
```q24.py
import string
def find_frequent_word(text):
text = text.lower()
return max(string.ascii_lowercase, key=text.count)
a = find_frequent_word("aiasfiah faihasjn8348 y5iHsuasHuUUUUUuuuurbuurugjsghfoas")
print(a)
[出典]ChekiO:The Most Wanted Letter
Q25 文字列の内最も連続された文字の個数を数える
これは、シンプルでありながら解き方が人によって異なり面白いため、2つ回答のパターンを載せておきます。
↓自分の解き方
def long_repeat(line):
if line=='':
return(0)
else:
count=1
count_chr=[1]
for i in range(1,len(line)):
if line[i-1]==line[i]:
count +=1
else:
count = 1
count_chr.append(count)
return max(count_chr)
↓別の解き方
def long_repeat(line):
count = 1
maxi = 1
if line != "":
for i in range(1,len(line)):
if line[i] == line[i-1]:
count+=1
if count > maxi:
maxi = count
else:
count = 1
return maxi
else:
return 0
[出典]ChekiO:Non-unique Elements
Q26: リスト問題
問題: 1. “mozzarella”,”cinderella”,”salmonella”(「モッツァレラ」「シンデレラ」「サルモネラ菌」) の3つの文字列を要素としてthingsというリストを作成 2. “mozzarella”の先頭文字を大文字にする 3. “cinderella”を全て大文字にする 4. “salmonella”を大文字にして、逆順にする。
#1
things = ["mozzarella","cinderella","salmonella"]
#2
things[0] = things[0].capitalize()
things
#3
things[1] = things[1].upper()
things
#4
things[2] = things[2].upper()
things[2] = things[2][::-1]
things[2] = things[2]
[出典]『入門 Python3』
Q27: 辞書問題
問題:
- e2fという英仏辞書を作り、それを表示 この辞書にはdogはchien,catはchat,walrusはmourseという情報が入っている。
- 辞書e2fを使って、walrusという単語に対応するフランス語を表示
- e2fからf2eという仏英辞書を作成
- e2fから英単語だけを集合の形で表示せよ
#1
e2f = {"dog":"chien","cat":"chat","walrus":"mourse"}
e2f
#2
e2f["walrus"]
#3
f2e = {}
for english, french in e2f.items(): #辞書のすべての値を取得するには、items()を使う
f2e[french] = english
f2e
#4
set(e2f.keys())
[出典]『入門 Python3』
Q28: 多重レベルの辞書問題
問題:
- lifeという多重レベルの辞書を作る。 “animals”,”plants”,”other”という最上位キーがあり、 animalsキーは”cats”,”octopi”,”emus”というキーを持つ他の辞書を参照する。 catsキーは”Henri”,”Grumpy”,”lucy”という文字列のリストを参照する。 他のキーは空辞書を参照する。
- lifeの最上位のキーを表示せよ
- life[“animals”]のキーを表示せよ
- life[“animals”][“cats”]の値を表示せよ
#1
life = {"animals":{
"cats":["Henri","Grumpy","lucy"],
"dogs":{},
"birds":{}},
"plants":{},
"other":{}
}
#2
print(life.keys())
#3
print(life["animals"].keys())
#4
print(life["animals"]["cats"])
[参考]『入門 Python3』
Q29: リスト内包表記を使って、rage(10)の偶数リストを作れ
even = [number for number in range(50) if number % 2 == 0]
even
[参考]『入門 Python3』
Q30: 辞書内包表記を使って、squaresという辞書を作れ
条件: キーの値は、range(10)を使ってキーを返し、各キーの自乗とする。
squares = {key: key * key for key in range(50)}
squares
[参考]『入門 Python3』