Correspondendo pares reversíveis em um arquivo CSV

1

Eu tenho um arquivo .csv que se parece com isso:

A,B,1999
C,D,1990
B,A,1989
D,A,1990
A,B,1999
...

Eu quero reorganizá-lo para parecer mais ou menos assim:

A,B,1989,0,B,A,1
A,B,1999,2,B,A,0
C,D,1990,1,D,C,0
D,A,1990,1,A,D,0

Em outras palavras, eu gostaria de ter o número de vezes que o par A,B ocorre para cada um dos valores registrados na terceira coluna, e também o número de vezes que B,A ocorre para o mesmo valor. / p>

Estou mais empenhado em combinar as linhas que dizem A,B com as que dizem B,A .

Agradeço muito qualquer ajuda com isso.

    
por nat 14.01.2018 / 18:37

2 respostas

1
Solução

GNU awk :

awk -F',' '{ k=$1 FS $2 }{ a[k][$3]++; rev[k]=$2 FS $1 }
           END{ 
               for(i in a) 
                   for(j in a[i]) { 
                       print i, j, a[i][j], rev[i], a[rev[i]][j]+0; 
                       delete a[rev[i]][j] 
                   }
           }' OFS=',' file

A saída:

C,D,1990,1,D,C,0
A,B,1999,2,B,A,0
D,A,1990,1,A,D,0
B,A,1989,1,A,B,0
    
por 14.01.2018 / 20:15
0

Este em Perl parece estar funcionando.

perl -F, -alne '
    next if /^\s*$/;
    $hs{$F[2]}{"$F[0],$F[1]"}++;
    END{
        while (my ($nr, $lhs) = each %hs) {
            while (my ($lts, $cnt) = each %{$lhs}) {
                my $rvs = scalar reverse $lts;
                my $rvsn = $hs{$nr}{$rvs} // 0;
                print "$lts,$nr,$cnt,$rvs,$rvsn";
                delete $hs{$nr}{$rvs};
            }
        }
    }
' data

Explicação linha por linha:

  1. Execute o Perl com , f ou delimitador, leia os campos em um a rray, cuide de l ine endings, execute para cada li n e e e xecute:

    perl -F, -alne '
    
  2. Ignorar linhas em branco na entrada:

    next if /^\s*$/;
    
  3. Aumenta o contador de hash de cada registro:

    $hs{$F[2]}{"$F[0],$F[1]"}++;
    
  4. Inicie o bloco final:

    END{
    
  5. Leia o hash:

    while (my ($nr, $lhs) = each %hs) {
        while (my ($lts, $cnt) = each %{$lhs}) {
    
  6. Prepare dados para impressão:

    my $rvs = scalar reverse $lts;
    my $rvsn = $hs{$nr}{$rvs} // 0;
    print "$lts,$nr,$cnt,$rvs,$rvsn";
    
  7. Livre-se da entrada dupla no hash:

    delete $hs{$nr}{$rvs};
    
  8. data é o arquivo de entrada.

Como resultado, para esses dados de entrada:

A,B,1999
C,D,1990
B,A,1989
D,A,1990
A,B,1999
B,A,1999

você deve obter esta saída:

D,A,1990,1,A,D,0
C,D,1990,1,D,C,0
B,A,1989,1,A,B,0
A,B,1999,2,B,A,1
    
por 15.01.2018 / 10:21

Tags