
Можете ли вы дать мне предложение, как мне сделать уникальную сортировку из строки или ряда? У меня есть такая информация:
Special c1,c2,c5,c7,c1,c2
Special2 C6
(это символ табуляции между Special
и c1...
).
Я хочу получить такой результат:
Special c1,c2,c5,c7
Special2 C6
Как мне этого добиться?
решение1
С использованиемэтот ответ,
perl -MList::MoreUtils=uniq -laF'\t' -ne '
$F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'
Это зависит от внешнего пакетаСписок::MoreUtils. Если вы не хотите устанавливать внешнюю зависимость, переопределите uniq
функциюеще несколько строк Perl. (Хотя у меня он, кажется, установлен как часть базовой системы на macOS.)
решение2
perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf
Объяснение
-F'\t|,'
=> разделит каждое поле записи на массив@F
поTAB
илиcomma
символов.-l
также установит значенияRS
tonewline
иORS
to .newline
-a
автоматически разделит каждую запись на слова на основеFS
выбранного-F
.-n
установит неявный цикл чтения записей на входеAND
и будет печатать данные только по запросу.-e
этоPerl
код, который будет выполняться для каждой записи входных данных на основеRS
выбранного-l
выше.- Первый элемент будет задан,
shift
а остальные элементы будутuniquified
сохранены как ключи хэша,%h
который будет регенерироваться каждый раз при считывании записи. Затем уникальные элементы сортируются, объединяются запятой и выводятся на печать.
решение3
Протестировано с OpenBSD awk
, GNU awk
и mawk
:
awk -F ',| +' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }' data.in |
sort -u |
awk '{ f[$1] = (f[$1] ? f[$1] "," : "") $2 } END { for (k in f) { print k, f[k] } }'
Первый awk
расширяет заданные данные до
Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6
Он использует как запятые, так и несколько пробелов в качестве разделителя полей, и для каждой записи (строки) ввода он печатает первое поле, а затем каждое из других полей по очереди на отдельных строках. Это предполагает, что в строках нет других пробелов или запятых, кроме тех, где они будут правильно интерпретироваться как разделители.
В sort
середине сортирует его по
Special2 C6
Special c1
Special c2
Special c5
Special c7
Он выполняет сортировку, используя полную строку в качестве ключа сортировки, и отбрасывает все повторяющиеся строки.
Последний awk
рекомбинирует данные в
Special c1,c2,c5,c7
Special2 C6
Он делает это, используя первое поле как ключ в ассоциативный массив и сохраняя разделенную запятыми конкатенацию соответствующих данных во втором поле как значение. В конце все собранные данные печатаются.
решение4
Другой способ в одну строку:
while read line; do echo "$line" | awk '{print $1}' | tr '\n' ' '; echo "$line" | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',' | sed -e 's/.$//g'; echo; done < file_to_sort
Он берет первый столбец каждой строки ( echo $line | awk '{print $1}' | tr '\n' ' ';
) и сортирует значения второго столбца, разделенные символом «,», после преобразования его в один столбец для применения sort
, а затем преобразует его обратно в одну строку с исходным форматированием ( echo $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ','
).
Делаем разбиение строк, как предлагает @tripleee:
while IFS=$'\t' read first second; do printf "%s\t%s\n" "$first" "$(tr ',' '\n' <<<"$second" | sort | tr '\n' ',' | sed -e 's/.$//g';)"; done < file_to_sort