Acrescentando dados a uma linha similar usando o awk

0

Eu tenho dados em um arquivo que se parece com o seguinte:

field11|field12|field13
field11|field12|field23
field11|field32|field33
field41|field42|field43
field41|field52|field43
field41|field62|field63

Como você vê, eu tenho 2 id field11 e field41 e eu quero que eles apareçam apenas uma vez para que pareça com isso:

field11|{'field12','field32'}|field13
field41|{'field42','field52','field62'}|field43

Eu quero que o terceiro campo seja o mesmo da primeira aparição para esse id. Cada ID ($ 1) tem $ 3 diferentes, enquanto o primeiro, o primeiro e o segundo campo permanecem iguais. Mas eu preciso imprimir o que vem na primeira linha para esse id. Como mostrado no exemplo, estamos imprimindo field13 e não field23.

Estou tentando conseguir isso com awk / sed . Eu sei uma solução para fazer isso com loops básicos no shell. mas preciso fazer isso em awk ou alguma ferramenta semelhante.

    
por b3219 03.06.2018 / 23:56

2 respostas

0

Uma solução awk ligeiramente longa (mas, esperamos, fácil de seguir):

BEGIN       { FS = OFS = "|" }

function output() {
    if (FNR == 1) return
    data = ""
    for (i in col2) {
        qi   = sprintf("'%s'", i);
        data = (data == "" ? qi : data "," qi)
    }
    print col1, sprintf("{%s}", data), col3
}

$1 == col1 && !($2 in col2) { col2[$2] }

$1 != col1    {
    output()
    col1 = $1; col3 = $3
    delete col2; col2[$2]
}

END { output() }

O bloco BEGIN apenas define o separador de campos de entrada e saída como | .

A função output() terá os dados recolhidos em col1 (a ID da primeira coluna), col2 (uma matriz de dados originais formar a segunda coluna) e col3 (o primeiro item de dados para esse ID específico da terceira coluna) e imprimi-lo. Ele itera sobre as chaves em col2 , citando-los individualmente e adicionando-os com vírgulas no meio para a variável de cadeia data . Em seguida, imprime col1 , data (dentro de chaves), e col3 .

O próximo bloco é executado quando encontramos uma entrada na segunda coluna que não vimos antes para esse ID específico. Apenas adiciona a segunda coluna como uma chave em col2 .

O bloco depois disso é executado quando encontramos um novo ID na primeira coluna. Ele chama output() e redefine as variáveis coletadas para começar a coletar dados para esse novo ID.

No bloco END , chamamos output() para a saída dos dados para o último ID.

Este programa não irá tentar armazenar o arquivo inteiro na memória de uma só vez, mas exige que os dados são classificados na primeira coluna.

Executando nos dados fornecidos:

$ awk -f script.awk file
field11|{'field12','field32'}|field13
field41|{'field42','field62','field52'}|field43
    
por 04.06.2018 / 09:12
0

Um bit perverso de perl:

perl -F'\|' -lane '
    $f2{ $F[0] }{ $F[1] } = 1;
    $f3{ $F[0] } = $F[2] if not exists $f3{ $F[0] }; 
  } END {
    for $key (sort keys %f2) {
        printf "%s|{%s}|%s\n", 
            $key, 
            join(",", map {chr(39) . $_ . chr(39)} sort keys %{$f2{$key}}), 
            $f3{$key};
    }
' file

As primeiras 2 linhas acumulam os dados usando matrizes associativas.
Em seguida, o bloco END faz um loop sobre os dados, formatos e impressões.

    
por 04.06.2018 / 13:01