Пример сортировки по Шварцу в "Обработке текста в Python"

Я просматривал «Обработку текста в Python» и попробовал его пример о сортировке Шварца.

Я использовал следующую структуру для образцов данных, которая также содержит пустые строки. Я отсортировал эти данные по пятому столбцу:
383230-49-78 1 100034 '06 текст '9562' текст '720' текст '867
335067-152-18 3 100030 'текст' 2400 'текст' 2342 'текст' 696
136592 21 230 3 100035 '03. текст '10368' текст '1838' текст '977

Код, используемый для сортировки по Шварцу:

for n in range(len(lines)):       # Create the transform
    lst = string.split(lines[n])
    if len(lst) >= 4:             # Tuple w/ sort info first
        lines[n] = (lst[4], lines[n])
    else:                         # Short lines to end
        lines[n] = (['\377'], lines[n])

lines.sort()    # Native sort

for n in range(len(lines)):       # Restore original lines
    lines[n] = lines[n][1]

open('tmp.schwartzian','w').writelines(lines)

Я не понимаю, как автор предполагал, что короткие или пустые строки должны идти в конец файла с помощью этого кода. Строки сортируются после структуры if-else, таким образом поднимая пустые строки в начало файла. Короткие строки, конечно, работают так, как предполагалось, с настраиваемой сортировкой (функция четвертого_слова), реализованной в примере.

Меня это беспокоит, есть идеи? Если я прав в этом, то как вы можете гарантировать, что короткие строки действительно останутся в конце файла?

Обновлено: Я заметил квадратные скобки вокруг "\ 377". Это испортило sort (), поэтому я удалил эти скобки, и вывод начал работать.

else:                         # Short lines to end
    lines[n] = (['\377'], lines[n])
print type(lines[n][0])
>>> (type 'list')

Я принял ответ nosklo за хорошее разъяснение значения '\ 377' и его улучшенный алгоритм. Большое спасибо и за другие ответы!

Если любопытно, я использовал образец файла размером 2 МБ, который занял 0,95 секунды с пользовательской сортировкой и 0,09 с сортировкой по Шварцу при создании идентичных выходных файлов. Оно работает!

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
680
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Не знаю, в чем вопрос, поэтому постараюсь в общих чертах прояснить ситуацию.

Этот алгоритм сортирует строки, получая 4-е поле и помещая его перед строками. Затем встроенный sort() будет использовать это поле для сортировки. Позже первоначальная линия восстанавливается.

Строки, пустые или короче 5 полей, попадают в часть else этой структуры:

if len(lst) >= 4:             # Tuple w/ sort info first
    lines[n] = (lst[4], lines[n])
else:                         # Short lines to end
    lines[n] = (['\377'], lines[n])

Он добавляет ['\377'] в первое поле списка для сортировки. Алгоритм делает это в надежде, что '\ 377' (последний символ в таблице ascii) будет больше, чем любая строка, найденная в 5-м поле. Таким образом, при сортировке исходная строка должна идти вниз.

Надеюсь, это проясняет вопрос. Если нет, возможно, вам следует указать, что именно вы хотите знать.

Лучшая общая версия того же алгоритма:

sort_by_field(list_of_str, field_number, separator=' ', defaultvalue='\xFF')
    # decorates each value:
    for i, line in enumerate(list_of_str)):
        fields = line.split(separator)
        try:
             # places original line as second item:
            list_of_str[i] = (fields[field_number], line)
        except IndexError:
            list_of_str[i] = (defaultvalue, line)
    list_of_str.sort() # sorts list, in place
    # undecorates values:
    for i, group in enumerate(list_of_str))
        list_of_str[i] = group[1] # the second item is original line

Предоставленный вами алгоритм эквивалентен этому.

Пустая строка не пройдет проверку

if len(lst) >= 4:

поэтому он будет иметь ключ сортировки ['\ 377'], а не 5-й столбец ваших данных, которым является lst[4] (lst[0] - это первый столбец).

Ну, он будет сортировать короткие строки почти в конце, но не всегда.

Собственно, и «наивная», и шварцевская версия ошибочны (по-разному). Nosklo и wbg уже объяснили алгоритм, и вы, вероятно, узнаете больше, если попытаетесь самостоятельно найти ошибку в шварцианской версии, поэтому я дам вам пока только подсказку:

Long lines that contain certain text in the fourth column will sort later than short lines.

Добавьте комментарий, если вам нужна дополнительная помощь.

Не имеет прямого отношения к вопросу, но обратите внимание, что в последних версиях python (я думаю, начиная с 2.3 или 2.4) преобразование и непреобразование могут выполняться автоматически с использованием аргумента key для sort() или sorted(). например:

def key_func(line):
    lst = string.split(line)
    if len(lst) >= 4:             
        return lst[4]
    else:                        
        return '\377'

lines.sort(key=key_func)

Хотя использование преобразования Шварца для Python довольно устарело, стоит упомянуть, что вы могли написать код таким образом, чтобы избежать возможности сортировки строки со строкой [4], начинающейся с \377, в неправильное место.

for n in range(len(lines)):
    lst = lines[n].split()
    if len(lst)>4:
        lines[n] = ((0, lst[4]), lines[n])
    else:
        lines[n] = ((1,), lines[n])

Поскольку кортежи сравниваются поэлементно, кортежи, начинающиеся с 1, будут отсортированы вниз по always.

Также обратите внимание, что тест должен быть len(list)>4 вместо >=.

Та же логика применяется при использовании современного эквивалента AKA функции key=.

def key_func(line):
        lst = line.split()
        if len(lst)>4:
            return 0, lst[4]
        else:
            return 1,

lines.sort(key=key_func)

Другие вопросы по теме