Transformando dados em colunas

1
 AC=126;AC_AFR=0;AC_AMR=0;AC_Adj=126;AC_EAS=120;AC_FIN=0;AC_Het=112;
 AC=12683;AC_AFR=4578;AC_AMR=559;AC_Adj=12680;AC_EAS=2104;AC_FIN=501;AC_Het=91966

Eu tenho dados com uma das colunas que se parecem com isso, ou seja, chaves e valores. Eu gostaria de transformar os dados selecionados em coluna com o cabeçalho sendo a chave e os valores na coluna.

Nem todas as linhas têm os mesmos dados. Algumas linhas não teriam campos que aparecem em outras linhas.

saída desejada:

AC      AC_AFR    AC_AMR and so on
126     0         0
12683   4578      559

Não sabe como fazer isso ou por onde começar

    
por Jan Shamsani 23.01.2017 / 06:04

3 respostas

1

Os desafios com isso são que os dados não são um arquivo de tipo CSV simples, em que a primeira linha é o nome das colunas e o restante das linhas são dados da coluna por linha.

Aqui você tem column_name = column_data, delimitado por ; characters. Minha solução seria usar uma linguagem como o Python para ler o arquivo em linha por linha. Eu criaria dict () de cada linha e um par de K: V para cada campo. Então eu adicionaria esse dict a uma lista () de todas as linhas.

Depois disso, posso processar a lista. Se eu estiver na primeira linha, vou imprimir os Nomes das Colunas, depois os valores, caso contrário, só imprimirei os valores.

Acho que o método seria semelhante em qualquer idioma que você esteja usando, mas é definitivamente factível.

Veja um exemplo rápido em Python que usa OrderedDicts para preservar a ordem "column":

#!/usr/bin/python
''' a quick example of a script to parse '=' delimited fields in 
    ';' delimited columns of a text file.
    prints tab delimited columnar data with headers to STDOUT
'''
from collections import OrderedDict

with open('data', 'rb') as infile:
    FLINES = infile.read().split()

DATA = []
for line in FLINES:
    fields = line.split(';')
    d = OrderedDict()
    for field in fields:
        if '=' in field:
            col, value = field.split('=')
            d.update({col: value})
    DATA.append(d)

L = 0
for D in DATA:
    if L == 0:
        print '\t'.join(D.keys())
    print '\t'.join(D.values())
    L += 1
  • Este exemplo pressupõe que todas as suas linhas terão as mesmas colunas, porque imprimirá apenas os nomes dos colônimos da primeira entrada que sair da lista.
por 23.01.2017 / 06:57
1

Solução rápida e suja com perl :

#!/usr/bin/env perl
use strict;
use warnings;

my %cache;
while (<>) {
    chomp;
    for my $pair ( split /;/ ) {
        $pair =~ s/=.*//;
        $cache{$pair} = 1;
    }
}
continue {
    last if eof;
}

my @keys = sort keys %cache;

print +( join "\t", @keys ), "\n";

while (<>) {
    chomp;
    my %h = map { m/([^=]+)=(\S+)/; ( $1, $2 ) } split /;/;
    print +( join "\t", map { $h{$_} // '' } @keys ), "\n";
}

Use assim:

perl script.pl input.txt input.txt

Isso verifica o arquivo de entrada duas vezes, primeiro para obter as chaves e, em seguida, para formatar as colunas. Está sujo porque provavelmente deve usar Text::CSV e Array::Unique .

    
por 23.01.2017 / 08:24
1

Usando o GNU awk

gawk -F '[=;]' '
    {for (i=1; i<NF; i+=2) values[$i][NR] = $(i+1)}
    END {
        PROCINFO["sorted_in"] = "@ind_str_asc"
        for (key in values) printf "%s\t", key
        print ""
        for (line=1; line<=NR; line++) {
            for (key in values) printf "%s\t", value[key][line]
            print ""
        }
    }
' filename
AC      AC_AFR  AC_AMR  AC_Adj  AC_EAS  AC_FIN  AC_Het  
126     0       0       126     120     0       112 
12683   4578    559     12680   2104    501     91966   

Estou usando 2 caracteres separadores de campo aqui, então todos os campos ímpares são as chaves e todos os campos pares são os valores.

    
por 23.01.2017 / 15:51