Как отсортировать файл по длине строки и потом по алфавиту по второму ключу?

Скажем, у меня есть файл:

ab
aa
c
aaaa

Я хотел бы, чтобы это было отсортировано так

c
aa
ab
aaaa

То есть сортировать по длине строки, а затем по алфавиту. Возможно ли это в Баше?

Мы призываем вопрошающих показать, что они пытались сделать до сих пор, чтобы решить проблему самостоятельно.

Cyrus 13.12.2020 15:20

@Anush: Не забудьте принять один из ответов!

user1934428 15.12.2020 15:06
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
2
943
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

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

< your_file awk '{ print length($0), $0; }' | sort -n | cut -f2

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

  • Я не думал, что строки могут начинаться с цифр, и поэтому я ожидал, что sort -n будет работать, потому что алфавитная и числовая сортировка дают одинаковый результат, если все строки имеют одинаковую длину, как в случае exaclty, потому что мы сортируем по длине строки, которая Добавляю через awk.

  • Оказывается, все работает, даже если в вашем вводе есть строки, начинающиеся с цифр, причина в том, что sort -n

    1. сортирует численно по первой числовой части строк;
    2. в случае ничьей он использует strcmp для сравнения целых строк

    Вот некоторые демо:

    $ echo -e '3 11\n3 2' | sort -n
    3 11
    3 2
    # the `3 ` on both lines makes them equal for numerical sorting
    # but `3 11` comes before `3 2` by `strcmp` before `1` comes before `2`
    
    $ echo -e '3 11\n03 2' | sort -n
    03 2
    3 11
    # the `03 ` vs `3 ` is a numerical tie,
    # but `03 2` comes before `3 11` by `strcmp` because `0` comes before `3`
    

    Таким образом, удачная часть заключается в том, что ,, который я включил в команду awk, вставляет пробел (на самом деле OFS), то есть нецифру, тем самым «нарушая» числовую сортировку и позволяя сортировке strcmp срабатывать (во всех строках, которые сравниваются в данном случае равны численно).

    Является ли это поведение POSIX или нет, я не знаю, но я использую GNU coreutils 8.32's sort. Обратитесь к этому моему вопросу и этому ответу на Unix для деталей.

awk может делать все сам, но я думаю, что использование sort для сортировки более идиоматично (например, использовать sort для сортировки) и эффективно, как объясняется в комментарии (в конце концов, почему бы вам не ожидать, что sort является наиболее эффективным инструментом в оболочка для сортировки вещей?).

сортировать более идиоматично.... Думаю, это не совсем аргумент. Однако sort может хорошо справляться с огромными файлами, в то время как с awk все должно уместиться в памяти, если вы хотите использовать встроенный sort awk; а если зайти так далеко, то я бы даже не использовал awk, а что-то вроде Perl или Ruby, что было бы более подходящим. Так что, в конце концов, это было бы для меня аргументом в пользу использования ... | sort Кстати, в вашем решении вы должны поместить сортировку по нескольким ключам прямо в пример кода, поскольку ОП запросил, чтобы для ключа равной длины сортировка должна выполняться по алфавиту.

user1934428 14.12.2020 13:26

@ user1934428, пожалуйста, посмотрите, нравится ли вам это сейчас. Что касается Ruby и Perl, то я их не знаю, поэтому даже не знаю, насколько они производительны. Думаю, вы могли бы добавить еще один ответ.

Enlico 14.12.2020 18:00

в случае ничьей он продолжает использовать алфавитную сортировку на основе остальной части строки: я не думаю, что это правда. На самом деле порядок не указан, и это просто происходит с вашим примером, но в общем случае может сломаться. Чтобы продемонстрировать это, я добавляю опцию -s, в которой говорится: «Сохранить исходный порядок, если вы не можете принять решение на основе предоставленных критериев сортировки: (echo 3 b; echo 3 a) | sort -n -s. На самом деле, я думаю, что ваша первоначальная идея явного указания двух ключей сортировки была лучше.

user1934428 15.12.2020 07:59

@ user1934428, пожалуйста, рассмотрите мой отредактированный ответ в свете вопроса, который я связал.

Enlico 15.12.2020 14:47

Я понимаю! Спасибо, что еще раз прямо указали мне на это.

user1934428 15.12.2020 15:06

@ user1934428, спасибо, что подтолкнули меня к расследованию. Как я писал в ответе мне повезло, я не знал этих подробностей которые я знаю сейчас.

Enlico 15.12.2020 15:07

Вставьте длину строки с помощью gawk (заполните нулями до четырех знаков, чтобы сортировка выполнялась правильно), отсортируйте по двум ключам (сначала по длине, затем по первому слову в строке), затем удалите длину:

gawk '{printf "%04d %s\n", length($0), $0}' | sort -k1 -k2 | cut -d' ' -f2-

Если это должен быть bash:

while read -r line; do printf "%04d %s\n" ${#line} "${line}"; done | sort -k1 -k2 | (while read -r len remainder; do echo "${remainder}"; done)

Для GNU awk:

$ gawk '{
    a[length()][$0]++                             # hash to 2d array
}
END {
    PROCINFO["sorted_in"] = "@ind_num_asc"          # first sort on length dim
    for(i in a) {
        PROCINFO["sorted_in"] = "@ind_str_asc"      # and then on data dim
        for(j in a[i])
            for(k=1;k<=a[i][j];k++)               # in case there are duplicates
                print j
        # PROCINFO["sorted_in"] = "@ind_num_asc"    # I don t think this is needed?
    }
}' file

Выход:

c
aa
ab
aaaa
aaaaaaaaaa
aaaaaaaaaa

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