Зацикливание в txt-файле

#python #file #txt

Вопрос:

У меня есть файл txt со списком исполнителей, песен и жанров в следующем формате:

 song 1
genre 1 
artist 1

song 2
genre 2
artist 2

etc.
 

Мне дают имя исполнителя, и если исполнитель есть в файле, я должен вернуть название их песни. Код, который мне удалось написать, это:

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

for art in artists:
    if art == artist:
 

Как я мог узнать название песни, которое находится на две строчки выше имени исполнителя? Также возможно, что исполнитель появляется несколько раз с разными песнями.

Комментарии:

1. Что делать, если у исполнителя несколько песен?

2. зачем вам это нужно header ? У вас нет никакого заголовка в файле примера

Ответ №1:

Сначала прочитайте свой файл в списке. Я предполагаю, что формат вашего файла исправлен: он содержит

  • Строка, указывающая название песни
  • Строка, указывающая жанр
  • Строка, указывающая исполнителя
  • Пустая строка
  • Повторять

Обратите внимание, что, поскольку заголовка, похоже, нет, вам не нужен начальный header = afile.readline()

Допустим, вы прочитали все строки своего файла в списке под названием 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
 

Теперь вы знаете, что

  • Начиная с первой строки, каждая четвертая строка-это название песни. Поэтому разрежьте lines список, чтобы занять каждую четвертую строку, начиная с первой строки, и сохраните его как список под названием songs
 songs = lines[0::4]
 
  • Сделайте то же самое для другой информации:
 genres = lines[1::4]
artists = lines[2::4]
 

Теперь мы можем zip() просматривать эти списки одновременно и печатать песни для исполнителей, которые соответствуют тому, что мы ищем:

 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   
 

Если бы вы делали это для группы художников, я бы рекомендовал вам сначала прочитать данные в словаре (или а collections.defaultdict ). Затем вы можете посмотреть значение словаря для данного исполнителя, и это будет намного быстрее, чем перебирать списки.

Чтобы учесть случай, когда у одного исполнителя может быть несколько песен, мы собираемся использовать словарь, где ключами являются имя исполнителя, а значениями-список, содержащий все песни, написанные ими.

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

Тогда все, что вам нужно сделать, это:

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

Вы можете избавиться от необходимости считывать весь файл в список, а затем обрабатывать его в словаре, читая файл построчно группами по четыре строки, но я оставлю это в качестве упражнения для вас.

Ответ №2:

Предполагая, что у каждого исполнителя есть только одна песня (или вы ищете первое совпадение), вы могли бы решить ее следующим образом:

 
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"

 

Ответ №3:

Начните со второго элемента (так как именно там находится первый исполнитель) и сканируйте каждый 4-й элемент в поисках исполнителя. Если i-th элемент linelist совпадает artist , выведите песню (которая находится по адресу i-2 ).

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

Комментарии:

1. afile.readlines() уже дает вам список

2. @PranavHosangadi Хорошая мысль.

Ответ №4:

Все ответы до сих пор действительны, но они основаны на том факте, что формат всегда составляет 4 строки. Вот код, который также работает, если отсутствуют данные или их больше:

 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})
 

Это также можно расширить, если ваш формат позже будет включать другую клавишу, например «альбом».

Если вы используете python3.10, вы можете изучить сопоставление шаблонов для дальнейшего упрощения кода.