Classificando exclusivamente em uma linha

Classificando exclusivamente em uma linha

Você pode me dar uma sugestão de como posso classificar exclusivamente a partir de uma linha ou linha? Tenho informações como esta:

Special   c1,c2,c5,c7,c1,c2   
Special2  C6

(este é um caractere TAB entre Speciale c1...).

Eu quero a saída assim:

Special   c1,c2,c5,c7  
Special2  C6

Como posso fazer isso?

Responder1

Usandoesta resposta,

perl -MList::MoreUtils=uniq -laF'\t' -ne '
    $F[1] = join(",", uniq(sort(split(",", $F[1])))); print join("\t", @F)'

Isso depende de um pacote externoLista::MaisUtilitários. Se você não deseja instalar uma dependência externa, reimplementar a uniqfunção éapenas mais algumas linhas de Perl. (Embora pareça que ele está instalado como parte do sistema básico do macOS.)

Responder2

perl -F'\t|,' -lane 'my %h; print shift @F, "\t", join ",", sort grep !$h{$_}++, @F' dataf

Explicação

  • -F'\t|,'=> dividirá cada campo de registro na matriz @Fou TABcaracteres comma.
  • -ldefinirá RSpara newlinee ORSpara newlinetambém.
  • -adividirá automaticamente cada registro em palavras com base na FSescolha de -F.
  • -nconfigurará um loop implícito de leitura de registro na entrada ANDe imprimirá coisas somente quando solicitado.
  • -eé o Perlcódigo a ser executado em cada registro da entrada com base na RSescolha -lacima.
  • O primeiro elemento será fornecido por shifte os demais elementos serão uniquifiedarmazenados como chaves de um hash, %h, que será regenerado toda vez que um registro for lido. Os elementos únicos são então classificados e unidos por vírgula e impressos.

Responder3

Testado com OpenBSD awk, GNU awke 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] } }'

O primeiro awkexpande os dados fornecidos em

Special c1
Special c2
Special c5
Special c7
Special c1
Special c2
Special2 C6

Ele usa vírgulas e múltiplos espaços como delimitador de campo e, para cada registro (linha) de entrada, imprime o primeiro campo seguido por cada um dos outros campos em linhas separadas. Isso pressupõe que não há outros espaços ou vírgulas nas linhas além de onde serão interpretados adequadamente como delimitadores.

O que sortestá no meio classifica em

Special2 C6
Special c1
Special c2
Special c5
Special c7

Ele faz uma classificação usando a linha completa como chave de classificação e descarta qualquer linha duplicada.

O último awkrecombina os dados em

Special c1,c2,c5,c7
Special2 C6

Ele faz isso usando o primeiro campo como chave em uma matriz associativa e armazena a concatenação separada por vírgula dos dados correspondentes no segundo campo como o valor. Ao final, todos os dados coletados são impressos.

Responder4

Outra maneira em uma linha:

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

Ele pega a primeira coluna de cada linha ( echo $line | awk '{print $1}' | tr '\n' ' ';) e classifica os valores da segunda coluna separados por ',' após convertê-los em uma única coluna para aplicar sorte depois convertê-los novamente em uma única linha com a formatação original ( echo $line | awk '{print $2}' | tr ',' '\n' | sort -u | tr '\n' ',').

Fazendo divisão de linha conforme sugerido por @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

informação relacionada