简体   繁体   中英

Select random lines from a text file without repeats in Python

I have a program which prints the first letter of songs and their artists and you have to guess the song.

I want the songs to be randomly selected, but only displayed once and I want the game to end once all the songs in the list have been displayed.

Here is an example of my text file 'songs.txt':

Billie Eilish - When The Party Is Over
Ariana Grande - boyfriend
TMC - No Scrubs
Destiny's Child - Say My Name
Adele - Hello
Katy Perry - California Girls
BTS - Home

Here is my output:

The first letter of the song is: H and the artist is: BTS

Here is my code:

   import random
   def random_line(songs):
       lines = open(songs).read().splitlines()
       return random.choice(lines)
   random =(random_line('songs.txt'))
   artist = (random.split(' - ')[0])
   song = (random.split(' - ',1)[1])
   song_letter = song[0]
   print ("The first letter of the song is: " + song_letter + " and the artist is: " + artist) 

I am assuming that you will be running this in some sort of while or for loop and may need to evaluate the user input against the actual stored input. So you may want to include a return artist, song_letter in the function. You're not getting the first letter because you're not indexing into the song far enough

import random

"""I've used a list of the songs you provided but you may wish to import these from a txt file and then convert to a list"""

songs = ['Billie Eilish - When The Party Is Over',
         'Ariana Grande - boyfriend',
        'TMC - No Scrubs',
        "Destiny's Child - Say My Name",
        "Adele - Hello",
        "Katy Perry - California Girls",
        "BTS - Home"]



def artist_song(song):
    artist = song.split(' - ')[0]
    song_letter = song.split(' - ')[1][0]
    print ("The first letter of the song is: " + song_letter + " and the artist is: " + artist)

    """You may chose to use return (artist,song_letter) insteas so you can use them for comparision"""

song = random.choice(songs) 
artist, song_letter = artist_song(song)
songs.remove(song)

You may wish to perform this multiple times until there are no loner any songs and you can do this as follows:


while songs:
    song = random.choice(songs) 
    artist, song_letter = artist_song(song)
    x = input('User input here: ').lower()
    if x == song.split(' - ')[1].lower():
        """What to do if their input matches"""
        pass
    else:
        """What to do if the song is wrong"""
        pass
    songs.remove(song)

With inputs, consider other factors such as input validation, so make sure that the user input is only letters and no numbers/spaces etc. You could include a counter to keep track of score.

store the random.choice(lines) in a variable and then delete it from lines list.

  def random_line(songs):
        lines = open(songs).read().splitlines()        
        random_line =  random.choice(lines)
        lines.remove(random_line)        
        return random_line

Here's a solution in the form of a generator, based on shuffling and implemented with yield . Shuffling takes O(n) time for a list of n items, which is amortized over the iterations to yield constant time per song. One advantage this has over delete-from-list solutions is that the generator can be run multiple times, as in the code below. It will iterate through the entire sequence but then will yield a different order if you keep requesting more songs.

import random

song_list = [
    "Billie Eilish - When The Party Is Over",
    "Ariana Grande - boyfriend",
    "TMC - No Scrubs",
    "Destiny's Child - Say My Name",
    "Adele - Hello",
    "Katy Perry - California Girls",
    "BTS - Home"
]

def song_info():
    random.shuffle(song_list)
    for i in range(len(song_list)):
        yield song_list[i].split(' - ')

def playlist():
    for (artist, title) in song_info():
        print ("The first letter of the song is: " + title[0] + " and the artist is: " + artist)

playlist()
print("That was so fun, let's do it again!")
playlist()

Obviously you could populate the song_list by reading from a file rather than hardwiring it into the code if you anticipate your "database" of songs growing.

It also might make more sense to store the data as lists/tuples of artist & title rather than as a string to be split. That would change the song_list and song_info() generator to:

song_list = [
    ("Billie Eilish", "When The Party Is Over"),
    ("Ariana Grande", "boyfriend"),
    ("TMC", "No Scrubs"),
    ("Destiny's Child", "Say My Name"),
    ("Adele", "Hello"),
    ("Katy Perry", "California Girls"),
    ("BTS", "Home")
]

def song_info():
    random.shuffle(song_list)
    for i in range(len(song_list)):
        yield song_list[i]

which is cleaner in my opinion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM