lbarros
lbarros

Reputation: 19

Looping through a txt file

I have a txt file with a list of artists, songs, and genres in the following format:

song 1
genre 1 
artist 1

song 2
genre 2
artist 2

etc.

I'm given an artists name and if the artist is in the file I have to return the name of their song. The code I've managed to write is:

afile = open('music.txt')
header = afile.readline()
artists = afile.readlines()
afile.close()

for art in artists:
    if art == artist:

How could I get the name of the song that is two lines above the artists name? It's also possible that an artists appears several times with different songs.

Upvotes: 1

Views: 362

Answers (4)

Frederik Rogalski
Frederik Rogalski

Reputation: 173

All answers until now are valid, but they do rely on the fact that the format is always 4 lines. Here is code that also does work if there is missing data or there is more data:

music = []
with open("music.txt") as f:
    for line in f:
        line = line.split()
        
        # continue if line is empty
        if not line:
            continue
        key = line.pop(0)
        value = ' '.join(line)
        
        # check for keys
        if key=='song':
            music.append({key: value})
        if key=='genre':
            music[-1].update({key: value})
        if key=='artist':
            music[-1].update({key: value})

This is also extendable if your format later includes another key like 'album'.

If you're using python3.10 you could look into pattern matching to further simplify the code.

Upvotes: 0

user12867493
user12867493

Reputation:

Start at the second element (as that is where the first artist is) and scan every 4th element for the artist. If the i-th element of linelist matches artist, print the song (which is at i-2).

for i in range(2, 100, 4):
    if linelist[i] == artist:
        print(linelist[i-2])

Upvotes: 0

pho
pho

Reputation: 25500

First, read your file into a list. I'm assuming the format of your file is fixed: it contains

  • A line specifying song name
  • A line specifying genre
  • A line specifying artist
  • A blank line
  • Repeat

Note that since there doesn't seem to be a header, you don't need the initial header = afile.readline()

Let's say you read all the lines of your file into a list called lines

lines = [line.strip() for line in afile] 
# You could also do 
# lines = afile.readlines()
# but that would leave behind trailing line breaks at the end of each line

Now, you know that

  • Starting at the first line, every fourth line is the song name. So slice the lines list to take every fourth line, starting at the first line and save it as a list called songs
songs = lines[0::4]
  • Do the same thing for the other information:
genres = lines[1::4]
artists = lines[2::4]

Now, we can zip() these lists to iterate over them simultaneously, and print the songs for the artists that match the one we're looking for:

look_for_artist = "artist 2"

print(f"Songs by {look_for_artist}:")
for artist, genre, song in zip(artists, genres, songs):
    if artist == look_for_artist:
        print(song, genre)
        # if you know that every artist has only one song, you can break the loop here since you found it already
        # break   

If you were doing this for a bunch of artists, I'd recommend you read the data into a dictionary (or a collections.defaultdict) first. Then, you can look up the value of the dictionary for the given artist and this will be much faster than looping over the lists.

To account for the case when a single artist can have multiple songs, we're going to use a dictionary where the keys are the artist's name, and values are a list containing all the songs by them.

import collections
lookup_dict = collections.defaultdict(list)
for artist, genre, song in zip(artists, genres, songs):
    lookup_dict[artist].append((genre, song))

Then, all you need to do is:

for genre, song in lookup_dict[look_for_artist]:
   print(song, genre)

You can remove the need to read the entire file into a list and then process it into a dictionary by reading the file line-by-line in groups of four lines, but I will leave that as an exercise for you.

Upvotes: 1

Eladtopaz
Eladtopaz

Reputation: 1054

Assuming that each artist has only one song (or you are searching for the first match) you could solve it like this:


def check_artist(chosen_artist):
    afile = open('music.txt')
    while afile:
        song = afile.readline()
        afile.readline() # Ignore the second line
        artist = afile.readline()
        if atrist == chosen_artist:
            return song.split("\n")
        afile.readline() # Ignore the empty line
    afile.close()
    return "The artists do not have a song"

Upvotes: 0

Related Questions