今回は受講生(T氏)からのお題を掘り下げていこう。Python学習素材としてとても良いお題だ。
実行例
まずは実行例から
1.宝くじを買う枚数を入力
2.0000~9999の重複のない番号から購入枚数選ばれる(昇順表示)
3. 当選番号が千の位から順番に1秒ごとに表示される(win環境の一部でうまく動きません、その場合はこの処理は省いてください)
4. 結果が表示される(1等は 完全一致,2等は下3桁,3等は…)
詳しくは以下の実行例を参照のこと
宝くじを何枚買いますか?>>5
['0406', '4131', '8321', '8708', '9871']
抽選開始...
5
1
3
1
1等賞(5131) []
2等賞(*131) ['4131']
3等賞(**31) []
4等賞(***1) ['8321', '9871']
作成
ではこのお題を順に作成していこう。任意の場所にlottery.pyを作成し以下のように記述する
import random,time
lotts=[ '{:04d}'.format(i) for i in range(10000)]
print(lotts)
実行してみよう。以下のように1万個表示されれば成功だ
解説
○今回はランダムと1秒ごとに止める処理が途中で出てくるので先頭でrandomとtimeモジュールをインポートしておく
○内包表記を使って0000~9999まで要素数1万個のリストを作成している。Pythonの内包表記は本当に便利だ。よくわからい人はここから学習してもらいたい。
今回はintで生成した0~9999を書式を使って’0000’~’9999’という文字列に変換している
続きを作ろう以下のハイライト部分のように修正する(print(lotts)はコメントアウト)
import random,time
lotts=[ '{:04d}'.format(i) for i in range(10000)]
#print(lotts)
n=int(input('宝くじを何枚買いますか?>>'))
my_lotts=sorted(random.sample(lotts,n))
print(my_lotts)
実行してみよう。枚数を聞かれるので適当な枚数を入力してみよう。以下のように表示されれば成功だ。
解説
○random.sample
なんて便利な命令が用意されているのだろうか。。。
random.sample(リスト,個数)
と指定するだけで、リストから指定個数分,重複なしに要素を取得しそれを構成要素としたリストを返してくれる。10000個のくじの中から重複なしに5個を選ぶという今回の処理にピッタリな命令だ。
こんな便利な命令が増えてきたらプログラマーはそのうちすることがなくなってしまうのではないだろうか?
○sorted
l=sorted(リスト)
とすることで昇順に並び替えたリストを新たに作成し返却してくれる。
my_lotts=sorted(random.sample(lotts,n))
1行でリストの中から重複なしに指定個数をピックアップし昇順に並び替えたリスト作る作業が終わってしまった。
続きを作ろう。以下のハイライト部分を追記する
import random,time
lotts=[ '{:04d}'.format(i) for i in range(10000)]
#print(lotts)
n=int(input('宝くじを何枚買いますか?>>'))
my_lotts=sorted(random.sample(lotts,n))
print(my_lotts)
lucky='{:04d}'.format(random.randrange(10000))
print('抽選開始...')
for c in lucky:
time.sleep(1)
print(c)
実行してみよう。当選番号が千の位から1秒毎に表示されれば成功だ。
解説
○random.randrange
random.randrange(10000)とすることで0~9999の値をランダムで一つ返してくれる。randint(1,10)は10を含むが,randrangeは未満になるので注意
lucky='{:04d}'.format(random.randrange(10000))
書式を用い整数を4文字の文字列に変換している。:04dとなっているのでもし4桁に満たない12などが出た場合は’0012’と0埋めしてくれる。
○time.sleep
time.sleep(10)
とすることで10秒処理を止めることができる。ミリ秒で渡す言語も多いがpythonのsleepは秒で渡す。もし、0.1秒止めたかったらsleep(0.1)と小数にして渡す
○for c in lucky:
luckyといのは’3471’のような文字列だが、pythonは文字列をそのままfor文にかけることができる。その場合、一文字ずつループで取り出す。今回はその変数をcharacterという意味でcとして受け取った。
続きを作ろう。以下のハイライト部分を追記する
import random,time
lotts=[ '{:04d}'.format(i) for i in range(10000)]
#print(lotts)
n=int(input('宝くじを何枚買いますか?>>'))
my_lotts=sorted(random.sample(lotts,n))
print(my_lotts)
lucky='{:04d}'.format(random.randrange(10000))
print('抽選開始...')
for c in lucky:
time.sleep(1)
print(c)
result=[[] for i in range(4)]
for lott in my_lotts:
if lucky == lott:
result[0].append(lott)
elif lucky[-3:]==lott[-3:]:
result[1].append(lott)
elif lucky[-2:]==lott[-2:]:
result[2].append(lott)
elif lucky[-1]==lott[-1]:
result[3].append(lott)
for i in range(len(result)):
print('{}等賞({:*>4s})'.format(i+1,lucky[i:]),result[i])
入力したら実行してみよう。
宝くじを何枚買いますか?>> 5
['0703', '1020', '1480', '3376', '6058']
抽選開始...
8
7
8
4
1等賞(8784) []
2等賞(*784) []
3等賞(**84) []
4等賞(***4) []
5枚くらいだとなかなか当たらない。1000枚くらい大人買いしてみよう。
表示がすごいことになってるがどうやら2等が当たったようだ。
解説
今回この1等が〜、2等が~というのを以下のような2次元リストで管理することにした
result=[
['4142'], # 1等の番号リスト
['0142','8142'], # 2等の番号リスト
['3542','9942'], # 3等の番号リスト
['0002','9992'], # 4等の番号リスト
]
なのでまずは空リストを4つ持つ2次元リストを以下のように作成する。
result=[[] for i in range(4)]
あとは、自分の持っている番号リストから1つずつ取り出しながら判定していくだけだ。
for lott in my_lotts:
if lucky == lott:
result[0].append(lott)
elif lucky[-3:]==lott[-3:]:
result[1].append(lott)
elif lucky[-2:]==lott[-2:]:
result[2].append(lott)
elif lucky[-1]==lott[-1]:
result[3].append(lott)
取り出した番号と当選番号が一致すればresult[0]にその番号をappend
そうではなくて下三桁が一致すればresult[1]に追加していっている
lucky[-3:]
今回は下三桁を強調する意味で[-3:]としているが今回は4文字とわかっているのでこの場合はlucky[1:]としても同じだ。スライスもバリエーションが多く難しいが便利なので少しずつ慣れていくしかない。
また、今回は当選番号が一つしかないので1等の番号は2等~4等のすべての当選条件を満たす。なのでif文の判定する順序には気を使う必要がある。
さて、最後の出力部分だ
for i in range(len(result)):
print('{}等賞({:*>4s})'.format(i+1,lucky[i:]),result[i])
rangeを使って0~3をインデックスiとして取り出した。このiを使ってresultリストから取り出している
:*>4s
この書式は文字列のスペースを4つ分用意して、文字を右詰めにして足りない部分は*で埋める書式だ。>の部分が右詰めを表す(<で左,^でセンタリング)
完成!
今回のお題を通して、乱数,ソート,スライス,書式,内包表記などを演習することができた。
コメント