Генератор, обеспечивающий минимальное расстояние между двумя элементами в списке

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

Файл содержит текст песни, хэштег и ссылку, разделенные символом /t, но я пытаюсь сделать код более гибким для любого изменения - добавления или удаления элемента из строки.

Проблема в псевдослучайном генераторе, который я беззастенчиво скопировал и не совсем понял. Я понял, что проблема в том, что матрица не является хэш-типом, а в генераторе я использую set() для ее хеширования. Как мне исправить код генератора для матрицы? Предполагается, что он должен выбирать строку случайным образом, но избегать того же выбора снова слишком близко.

Это код:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import random, collections, time

# Pseudo-random generator
def choice_gen(choices, min_dist):
    last_choices = collections.deque(maxlen=min_dist)
    choices = set(choices)
    while 1:
        c = random.choice(list(choices - set(last_choices)))
        last_choices.append(c)
        yield c

# Organizes the contents of the file in matrix 
# <Song lyric> <hashtag> <link>
songs_table = []
with open("songs.txt") as f:
    for txtline in f:
        song_data= txtline.split('\t')
        songs_table.append(song_data)

# Prints a pseudo-random row of the matrix
for song_data in choice_gen(songs_table,2):
    print "{}".format(song_list)
    time.sleep(2)

# With dictionary, only 2 values per song though,
# the script runs without issues here
# <Lyric> <hashtag>
"""     
song_dict = {}
with open("songs.txt") as f:
    for txtline in f:
        (key, val) = txtline.split('\t')
        song_dict[key] = val

for line in choice_gen(song_dict.items(),2):
        print "{}".format(line)
        time.sleep(2)
"""

1 ответ

Решение

list объекты являются изменяемыми, поэтому не могут быть хэшами. Используйте кортежи, которые не являются изменяемыми, поэтому hashable:

songs_table = []
with open("songs.txt") as f:
    for txtline in f:
        song_data= tuple(txtline.split('\t'))
        songs_table.append(song_data)

Быстрая демонстрация:

>>> some_nested_list = [['foo', 'bar', 'baz'], ['spam', 'ham', 'eggs']]
>>> set(some_nested_list)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> set(tuple(el) for el in some_nested_list)
set([('foo', 'bar', 'baz'), ('spam', 'ham', 'eggs')])
Другие вопросы по тегам