Я просматривал «Обработку текста в 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 с сортировкой по Шварцу при создании идентичных выходных файлов. Оно работает!






Не знаю, в чем вопрос, поэтому постараюсь в общих чертах прояснить ситуацию.
Этот алгоритм сортирует строки, получая 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)