私は自分の学校のために宝くじプログラムを作ろうとしています (私たちは経済システムを持っています)。
私のプログラムは数値を生成し、それをテキスト ファイルに保存します。ジェネレーターから数字を「引き出し」たいときは、勝者が確実に存在するようにしたいのです。
Q: Python にテキスト ファイルからランダムな行を選択させ、その番号として出力を与えるにはどうすればよいですか?
私は自分の学校のために宝くじプログラムを作ろうとしています (私たちは経済システムを持っています)。
私のプログラムは数値を生成し、それをテキスト ファイルに保存します。ジェネレーターから数字を「引き出し」たいときは、勝者が確実に存在するようにしたいのです。
Q: Python にテキスト ファイルからランダムな行を選択させ、その番号として出力を与えるにはどうすればよいですか?
Python にテキスト ファイルからランダムな行を選択させ、その番号として出力を与えるにはどうすればよいですか?
ファイルが比較的小さいと仮定すると、おそらく次の方法が最も簡単な方法です。
import random
line = random.choice(open('data.txt').readlines())
ファイルが非常に大きい場合、ファイル サイズを指定してファイル内のランダムな場所をシークし、次の完全な行を取得できます。
import os, random
def get_random_line(file_name):
total_bytes = os.stat(file_name).st_size
random_point = random.randint(0, total_bytes)
file = open(file_name)
file.seek(random_point)
file.readline() # skip this line to clear the partial line
return file.readline()
def random_line():
line_num = 0
selected_line = ''
with open(filename) as f:
while 1:
line = f.readline()
if not line: break
line_num += 1
if random.uniform(0, line_num) < 1:
selected_line = line
return selected_line.strip()
ここで示したアプローチのほとんどは機能しますが、ファイル全体を一度にメモリにロードする傾向があります。しかし、このアプローチではありません。したがって、ファイルが大きい場合でも、これは機能します。
このアプローチは、一見するとあまり直感的ではありません。この背後にある定理は、N 行を見たときに、これまでにそれぞれの行が選択される確率が正確に 1/N であると述べています。
「Pythonクックブック」の123ページより
私の頭の上から:
import random
def pick_winner(self):
lines = []
with open("file.txt", "r") as f:
lines = f.readlines();
random_line_num = random.randrange(0, len(lines))
return lines[random_lines_num]
入力ファイルを少し変更すると (最初の行にアイテムの数を格納する)、ファイル全体を最初にメモリに読み込まなくても、一様に数を選択できます。
import random
def choose_number( frame ):
with open(fname, "r") as f:
count = int(f.readline().strip())
for line in f:
if not random.randrange(0, count):
return int(line.strip())
count-=1
100 個の数字があるとします。最初の数字を選ぶ確率は 1/100 です。2 番目の数字を選択する確率は (99/100)(1/99) = 1/100 です。3 番目の数字を選択する確率は、(99/100)(98/99)(1/98) = 1/100 です。正式な証明は省略しますが、100 個の数字のいずれかを選択する確率は 1/100 です。
最初の行にカウントを格納することは厳密には必要ではありませんが、行をカウントするためだけにファイル全体を読み取らなければならないという手間を省くことができます。いずれにせよ、ファイル全体をメモリに保存して、同じ確率で任意の 1 行を選択する必要はありません。
別のアプローチ:
import random, fileinput
text = None
for line in fileinput.input('data.txt'):
if random.randrange(fileinput.lineno()) == 0:
text = line
print text
分布:
$ seq 1 10 > data.txt
# run for 100000 times
$ ./select.py > out.txt
$ wc -l out.txt
100000 out.txt
$ sort out.txt | uniq -c
10066 1
10004 10
10023 2
9979 3
9926 4
9936 5
9878 6
10023 7
10154 8
10011 9
歪みは見られませんが、おそらくデータセットが小さすぎます...
私はpythonチュートリアルを見て、このスニペットを見つけました:
def randomLine(filename):
#Retrieve a random line from a file, reading through the file once
fh = open("KEEP-IMPORANT.txt", "r")
lineNum = 0
it = ''
while 1:
aLine = fh.readline()
lineNum = lineNum + 1
if aLine != "":
#
# How likely is it that this is the last line of the file ?
if random.uniform(0,lineNum)<1:
it = aLine
else:
break
nmsg=it
return nmsg
#this is suposed to be a var pull = randomLine(filename)