Проблема: метод append() не сохраняет исходный порядок строк в текстовом файле

#python #python-3.x #list #sorting

#python #python-3.x #Список #сортировка

Вопрос:

У меня есть функция create_profanity_output() (см. Ниже весь код), в которой каждая ненормативная лексика из файла расшифровки добавляется в список, за которым следуют временные метки и символы цензуры. Я хочу сохранить порядок, в котором элементы отображаются в расшифровке.

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

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

 # Current output in wrong order.
[['fart', '00:00:03,950', '00:00:06,840', '****'],
 ['damn', '00:00:03,950', '00:00:06,840', '****'],
 ['damn', '00:00:03,950', '00:00:06,840', '****'],
 ['erotic', '00:00:03,950', '00:00:06,840', '****'],
  

Но внешний вид элементов в файле 1) fart, 2) эротический, 3) проклятый, 4) проклятый, поэтому желаемый результат будет:

 # Target output in correct order.
[['fart', '00:00:03,950', '00:00:06,840', '****'],
 ['erotic', '00:00:03,950', '00:00:06,840', '****'],
 ['damn', '00:00:03,950', '00:00:06,840', '****'],
 ['damn', '00:00:03,950', '00:00:06,840', '****'],
  

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

sorted_output = sorted(profanity_output, reversed=True) ,

sorted_output = sorted(profanity_output, reversed=False) ,

sorted_output = sorted(profanity_output, key=lambda x: x[0]) ,

и тому подобное, но без достижения моей цели.

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

Весь код:

 def create_profanity_output():
    """Create a list 'profanity_output' which shall contain each profanity,
    its timestamp and the default censor characters ('****')."""
    profanity_output = []

    # Define censor characters that occur in the transcript.
    censor_chars = "****"

    # Create lists with transcript data.
    line_numbers = []
    timestamps = []
    text_lines = []

    # Get lines from the transcript that contain strings according to the
    # following pattern: 'line number', 'timestamp', 'text line', '' (empty
    # string).
    lines = transcript.splitlines()

    # Iterate over 'lines' to get each single element from it. Divide the
    # range object by 4 because of the 'lines' object's structure: (0: line
    # number, 1: timestamp, 2: text line, 3: empty string).
    for x in range(int(len(lines) / 4)):
        # Increment iterable by 4. The * sign allows to always move 4
        # elements further to the next "profanity cycle".
        x = x * 4
        # Add relevant elements to lists.
        line_numbers.append(lines[x])
        timestamps.append(lines[x   1])
        text_lines.append(lines[x   2])
        
    # Iterate over transcript data and create a zip object.
    for line_number, timestamp, text_line in zip(line_numbers, timestamps,
                                                 text_lines):
        # Create a list with timestamp strings: '00:00:03,950', '-->',
        # '00:00:06,840'.
        time_splits = timestamp.split()

        for swearword in wordlist.splitlines():
            # Iterate over tokenized text lines.
            for word in text_line.split():
                if word == swearword:
                    profanity_output.append([word, f"{time_splits[0]}", 
                                             f"{time_splits[2]}",
                                             censor_chars])

    return profanity_output

# Call function.
profanity_output = create_profanity_output()
print(profanity_output)

  

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

1. Можем ли мы увидеть ваш ввод?

2. Однако вам обязательно следует изменить способ поиска по ругательствам. Было бы лучше разобрать wordlist один раз как a set и посмотреть, если word in swearword_set .

3. Просто переключите вложенные циклы for for swearword... и for word... . Внешний цикл управляет порядком.

4. @MichaelButscher: Ура, теперь это работает! Большое вам спасибо!

Ответ №1:

Как упоминал Майкл Бутчер в комментариях, ваша проблема в том, что for loops они расположены в неправильном порядке. В настоящее время порядок вашего списка ругательств определяет порядок добавления слов в том же text_line самом. Переключение порядка циклов даст вам правильный порядок.

Однако лучшим решением является предварительный анализ ваших ругательств. Это по-прежнему сохранит порядок слов, упорядоченный в text_line , но также ускорит поиск (и это просто лучшая практика, даже если вам не нужна скорость).

 swearwords = set(wordlist.splitlines())
for word in text_line.split():
    if word in swearwords:
    ...

  

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

1. Спасибо за ваш ответ и ваше объяснение, а также за дополнительный совет по разбору ругательств. Я скорректирую это в своем коде.

Ответ №2:

Ваш вывод для одной и той же строки фактически упорядочен по порядку ругательств в wordlist . Итак, вы сначала выбираете ненормативную лексику, а затем просматриваете строку, чтобы увидеть, существует ли она. На самом деле вам нужно сначала выполнить итерацию по строке. Вы также можете использовать __contains__ функцию списка, чтобы увидеть, действительно ли ваше слово является ругательством.

Вот так:

         swearwords = wordlist.splitlines()
        # Iterate over tokenized text lines.
        for word in text_line.split():
            if word in swearwords:
                profanity_output.append([word, f"{time_splits[0]}", 
                                         f"{time_splits[2]}",
                                         censor_chars])