从文件中随机打印不重复的行-Python

7
我有一个小程序,它会从文本文件中随机打印出一些行。我想要将已选择的行保存在列表或其他东西中,这样下次就不会重复了。 示例

text_database.txt

  1. 这是一行
  2. 这是另一行
  3. 这是一个测试行
  4. 那很糟糕
这是一个示例,展示了输出是随机的,并且程序会重复输出某些行 - 这不是在终端中的直接输出结果。
This is a line
That sucks
That sucks
That sucks
This is a line

我的代码:

# Variable for text file
text_database = './text_database.txt'

...

with open (text_database) as f:
    lines = f.readlines()
    print(random.choice(lines))

我尝试了:

with open (text_database) as f:
    lines_list = []
    lines = f.readlines()
    random_tmp = random.choice(lines)
    if random_tmp not in lines_list:
        lines_list.append(random_tmp)
        print(random_tmp)

它不起作用,我需要帮助。谢谢大家。


2
这个程序运行时是否只打印文件中的一行随机内容,然后程序就结束了?为了明确起见,您想要保存已打印的行跨程序执行的不同情况吗?编辑:否则我不知道为什么它会打印5次,也不确定elif周围是什么。 - Sean Breckenridge
这是一个 Telegram 机器人,消息将打印在热敏打印机上。因此,程序一直在运行,并在程序运行时从文件中打印行。第一个代码块运行得很好。是的,我想保存已经打印的行,这样下次程序就会选择另一行。输出只是为了向您展示程序重复行。这不是直接输出。它只打印一次。对于混淆造成的困扰,我感到抱歉。 - xmaxiy
你没有更新 lines_list,这是你的问题的来源吗?而且将其作为一个 set 会更有效率,而不是一个 list - Mark Ransom
6个回答

5
from random import sample

file_name = "text_database.txt"
lines = open(file_name, "r").read().splitlines()

for line in sample(lines, k=len(lines)):
    print(line)

我使用.read().splitlines() 替代 .readlines()来删除每行的尾随空格(换行符)。我也可以这样做:
lines = [line.rstrip("\n") for line in open(file_name, "r")]

以下是来自文档的random.sample的描述:

从序列中随机选择k个不重复的元素组成列表。用于无重复的随机取样。

或者,您可以对行列表进行洗牌,然后迭代遍历它们。

编辑 - 我现在明白了,这样怎么样?

def main():

    from random import shuffle

    file_name = "text_database.txt"
    lines = open(file_name, "r").read().splitlines()
    shuffle(lines)

    sentinel = object()

    def command_random():
        try:
            line = lines.pop()
        except IndexError:
            print("There are no more lines in the file!")
        else:
            print(line)

    def command_quit():
        nonlocal sentinel
        sentinel = None

    commands = {
        "random": command_random,
        "quit": command_quit
    }

    while sentinel is not None:
        user_input = input("Please enter a command: ")
        command = commands.get(user_input)
        if command is None:
            continue
        command()

    return 0


if __name__ == "__main__":
    import sys
    sys.exit(main())

为什么要使用 splitlines(),为什么要使用 sample(...)?能否多解释一些? - stovfl
谢谢你的回答。程序不会重复输出行。问题是,它会打印文件中的所有行,但我只想打印文件中的一行,而且不能重复。 - xmaxiy
当你说“无重复”时,你的意思是,运行程序一次,它会打印出一个随机行,再次运行程序,它会打印出另一行不同的随机行(即在先前执行程序的过程中未曾打印过的行)? - Paul M.
不,我在上面的注释中已经描述了它。这是一个Telegram机器人,程序一直在运行。当我打开一个命令时,我想从文件中打印一行,在这种情况下是 /random。下次运行该命令时,我想要从文本文件中打印另一行。而不是相同的那一行。 - xmaxiy

4

这是一个非常混乱的解决方案,但在此之前我已经进行了测试。


f = open(text_database, "r")

list = []
list_of_nums = []

for i in f:
    list.append(i)

elif command == '/random':

    randomNum = random.randint(0, len(list) - 1)

    def reRun():
        global randomNum
        for i in list_of_nums:

            if randomNum == i:
                randomNum = random.randint(0, len(list) - 1)
                reRun()


    reRun()
    list_of_nums.append(randomNum)

    print(list[randomNum])

这段代码的作用是遍历文件f中的所有行,并将它们放入一个列表中。然后从0到列表长度之间随机选择一个数字,并打印相应的随机行。

希望能对你有所帮助!欢迎来到stack overflow!


谢谢你的回答。如果我没错的话,程序会打印出一个随机行,有可能会重复 - 我是对的吗? - xmaxiy
哦,抱歉,现在我重新阅读了你的问题,我知道你想要什么了。给我几分钟,我会编辑它。 - gerard Garvey
我已经解决了这个问题,但是代码非常混乱,我现在会编辑帖子。 - gerard Garvey

3
你的代码存在问题,如果你遇到已经显示过的行,你只是返回并什么也不做。
通过对代码进行小的调整,你可以选择一个新的随机行,直到找到一个你还没有选择过的。这可以使用while块完成:
# Variable for text file
text_database = './text_database.txt'
#List of already chosen lines
lines_list = []

# Elif instruction for random lines from file
elif command == '/random':
    with open (text_database) as f:
        lines = f.readlines()
        random_tmp = random.choice(lines)
        #while line has been chosen already, try to chose another one
        while random_tmp in lines_list:
            random_tmp = random.choice(lines)
        lines_list.append(random_tmp)
        print(random_tmp)

请注意,此代码存在一些限制:

  • 一旦选择了所有行,循环将永远运行
  • 记住已选择的文本行可能会消耗大量内存,您可以记住已选择的行的索引。

3
elif command == '/random':
    with open (text_database) as f:
        lines = f.readlines()

    while len(lines)>0:
        max_int = len(lines)-1 #update the len each loop as we remove one each time
        print(lines.pop(random.randint(0, max_int))) #pop a random value from the list

谢谢你的回答。问题是,程序打印文件中所有行而不重复。但我只想打印一行。 - xmaxiy

2

尝试使用这个解决方案,它每次只打印一行随机数据。

import random
text_database = './text_database.txt'
lines_list = []
with open (text_database) as f:
    lines = f.readlines()
    lines_list.append(lines)
for item in lines_list:
    rand_item = item[random.randrange(len(item))]
print(rand_item)

谢谢您的回答。但是程序打印了重复的行。 - xmaxiy
你能解释一下“duplicated”的意思吗? - Sara Nabil

1
嘿,这个版本更加简洁,并且包含了您所要求的所有功能。
f = open(text_database, "r")

list = []

for i in f:
    list.append(i)

elif command == '/random':

    random.shuffle(list)

    for i in list:

        print(i)

这会获取文件中的所有行,并使用Python内置的random.shuffle对它们进行洗牌。没有重复的可能性,而且相当高效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接