Qual é a maneira mais fácil de verificar se os valores das colunas A e B são bidirecionais com o AWK? [fechadas]

4

Qual é a maneira mais fácil de verificar se os valores das colunas A e B ocorrem nos dois sentidos?

Saída para verificar:

Mike John
John Mike
Pamela Barbara
Barbara Pamela
Mike Paul
Roger Paul

Saída desejada

Mike <-> John
Pamela <-> Barbara
Mike -> Paul
Roger -> Paul

PS.

Primeiro, pode ser como procurar todos os valores possíveis nas colunas A e B e, em seguida, fazer contagem de palavras para cada linha

Mike John 1 1
Pamela Barbara 1 1
Mike Paul 1 0 
Roger Paul 1 0

Em seguida, a alteração é enviada para a desejada.

    
por tiny 12.09.2012 / 08:39

6 respostas

2

Se o pedido não for um problema, você pode usar essa solução de hash em awk .

BEGIN { d = "|" }
{
  if(names[$2 d $1] > 0)
    ++names[$2 d $1]
  else
    ++names[$1 d $2]
}

END { 
  for(n in names) { 
    split(n, a, d)
    if(names[n] >= 2)
      print a[1] " <-> " a[2]

    if(names[n] == 1)
      print a[1] " -> " a[2]
  }
}

O valor de hash é inicializado para a concatenação dos dois nomes delimitados por um pipe (a variável d ); se esses nomes ocorrerem novamente em ordem oposta, esse elemento em particular no hash é incrementado para 2.

Saída:

Pamela <-> Barbara
Mike -> Paul
Roger -> Paul
Mike <-> John
    
por 12.09.2012 / 10:27
1

Bem, desde que você marcou essas , apesar de seu título :

#!/usr/bin/env python

input_file    = 'input.dat'    
out_data      = []
relationships = []

in_fh = open(input_file, 'r')
for line in in_fh:
    x, y = line.split()

    # If the reverse mapping was already seen...
    if (y, x) in out_data:    
        # ... then update the reverse mapping to point both ways
        idx = out_data.index( (y, x) )
        relationships[idx] = '<->'

    # Otherwise, we have no reverse mapping yet...
    else:
        # if we haven't seen the forward mapping yet either...
        if (x, y) not in out_data:    
            # ...then record the forward mapping
            out_data.append( (x, y) )
            relationships.append('->')

in_fh.close()    

# Print the final mappings
for (x, y), arrow in zip(out_data, relationships):
    print "%s %s %s" % (x, arrow, y)
    
por 12.09.2012 / 09:34
0

Esta é a tentativa do meu script failed para evitar o uso de arrays ou hashes. ( bothways.txt file contém os dados do exemplo).

#!/bin/bash

sourcefile=bothways.txt
reversefile=bothways2.txt
dupefile=bothways3.txt

# Create reverse file by swapping the columns
sed -r 's/(\w+)(\s+)(\w+)//g' <$sourcefile >$reversefile

# Create dupe file by concatenating source and reverse files
# and displaying the duplicate lines
cat $sourcefile $reversefile | sort | uniq -d >$dupefile

while read line
do
    if grep "$line" $dupefile >/dev/null
    then
        arrow='<->';
    else 
        arrow='->';
    fi
    echo $line | sed -r "s/(\w+)\s+(\w+)/ $arrow /g"
done < $sourcefile

Saída:

Mike <-> John
John <-> Mike
Pamela <-> Barbara
Barbara <-> Pamela
Mike -> Paul
Roger -> Paul

O problema com a saída é que ela contém linhas redundantes. (Embora as relações estejam corretas.)

    
por 12.09.2012 / 11:04
0

Esta versão perl espera entrada em stdin ou de nomes de arquivos especificados na linha de comando e imprime resultados para stdout.

Ele usa um hash para rastrear quantas vezes viu os mesmos valores juntos (ignorando as linhas subseqüentes, a menos que estejam em ordem inversa à primeira). Duas vezes significa que a relação entre a coluna A e a coluna B é bidirecional A < - > B, enquanto que uma vez significa unidirecional de A- > B.

Os hashes são inerentemente não-ordenados, então podemos usar a seguinte matriz para preservar a ordem das linhas de entrada e imprimir os resultados em uma ordem similar (não será exatamente a mesma porque só imprimimos AB mesmo se BA também foi vista )

Se a ordem da saída não for importante, comente ou exclua a linha my @order e a linha push e troque o caractere de comentário nas duas versões das linhas foreach abaixo.

#! /usr/bin/perl 

use strict;

# hash keys will be 'columnA-columnB', we'll split them when we print the report.
my %AB=();
my @order=();

while(<>) {
    chomp;
    my ($A, $B) = split;

    # have we seen a key B-A?  if so, increment that rather than define A-B
    if (defined($AB{$B . '-' . $A})) {
        $AB{$B . '-' . $A} = 2;
    } elsif (! defined($AB{$A . '-' . $B})) {
        $AB{$A . '-' . $B} = 1;
        push @order, $A . '-' . $B;
    }
}

#foreach my $key (sort keys %AB) {
foreach my $key (@order) {
    my ($A,$B) = split /-/,$key;

    if ($AB{$key} == 1) {
        print "$A -> $B\n";
    } elsif ($AB{$key} == 2) {
        print "$A <-> $B\n";
    } ;
}

Saída:

Mike <-> John
Pamela <-> Barbara
Mike -> Paul
Roger -> Paul
    
por 12.09.2012 / 11:30
0

aqui o mesmo algoritmo no bash

#!/bin/bash

while read n1 n2; do
  n1=${n1//[^[:alpha:]]}
  n2=${n2//[^[:alpha:]]}
  n=___${n2}_$n1
  k=${!n}
  if ((k>0)); then
    ((___${n2}_$n1++))
  else
    ((___${n1}_$n2++))
  fi
done

for n in ${!___*}; do
  k=${!n}
  n=${n:3}
  if ((k>=2)); then
    echo "${n/_/ <-> }"
  elif ((k==1)); then
    echo "${n/_/ -> }"
  fi
done
    
por 12.09.2012 / 16:36
0

Uma solução python que funciona para seus dados de exemplo, fornecendo a mesma saída:

Ao contrário de alguns outros exemplos, isso lembra uma linha de entrada e produz saída em ordem.

paddy$ more tmpt.txt tmpt.py 
::::::::::::::
tmpt.txt
::::::::::::::
Mike John
John Mike
Pamela Barbara
Barbara Pamela
Mike Paul
Roger Paul
::::::::::::::
tmpt.py
::::::::::::::
lastwords = []
with file('tmpt.txt') as f:
    for line in f:
        words = line.strip().split()
        if words[::-1] == lastwords:
            print(' <-> '.join(lastwords))
            words = []
        elif lastwords:
            print(' -> '.join(lastwords))
        lastwords = words
if lastwords:
    print(' -> '.join(lastwords))

paddy$ python tmpt.py
Mike <-> John
Pamela <-> Barbara
Mike -> Paul
Roger -> Paul
paddy$ 
    
por 18.09.2012 / 08:10