J'ai deux fichiers délimités par des tabulations, le fichier 1 contient des identifiants et le fichier 2 a des valeurs liées à ces identifiants (ou dire que c'est un très gros dictionnaire).

Fichier 1

Ronny
Rubby
Suzie
Paul

Le fichier 1 n'a qu'une seule colonne.

Fichier 2

Alistar Barm Cathy Paul Ronny Rubby Suzie Tom Uma Vai Zai
12      13    14   12     11   11   12    23 30  0.34 0.65
1       4     56   23     12   8.9  5.1   1  4    25  3

N nombre de lignes sont présentes dans le fichier 2.

Ce que je veux, si les identifiants du fichier 1 sont présents dans le fichier 2, je devrais avoir toutes les valeurs qui lui sont liées dans un autre fichier délimité par des tabulations.

Quelque chose comme ça:

Paul Ronny Rubby Suzie
12     11   11   12
23     12   8.9  5.1

Merci d'avance.

0
Angelo 8 déc. 2011 à 17:45

7 réponses

Meilleure réponse

Un exemple en Python qui fait le travail en stream (ie: pas besoin de charger le fichier complet avant de démarrer la sortie):

# read keys
with open('file1', 'r') as fd:
    keys = fd.read().splitlines()

# output keys
print '\t'.join(keys)

# read data file, with header line and content
with open('file2', 'r') as fd:
    headers = fd.readline().split()
    while True:
        line = fd.readline().split()
        if len(line) == 0:
            break
        print '\t'.join([line[headers.index(x)] for x in keys if x in headers])

Production:

$ python test.py 
Ronny   Ruby    Suzie   Paul
11      11      12      12
12      8.9     5.1     23
1
tito 8 déc. 2011 à 14:20

REMARQUE

Votre exemple de sortie n'est PAS correct, car là vous avez "Ruby" mais dans votre exemple file1 vous aviez "Rubby" Ruby = / = Rubby

kent$  awk 'NR==FNR{t[$0]++;next}
{if(FNR==1){
        for(i=1;i<=NF;i++)
                if($i in t){
                        v[i]++;
                        printf $i"\t";
                }
        print "";
        }else{
        for(x in v)
                printf $x"\t"
        print "";
}

}' file1 file2

sortie

Paul    Ronny   Suzie
12      11      12
23      12      5.1
4
Kent 8 déc. 2011 à 13:57
$ awk 'FILENAME~1{a[$0];next};FNR==1{for(i=1;i<=NF;i++)if($i in a)b[i]};{for(j in b)printf("%s\t",$j);print ""}' file{1,2}.txt
Paul    Ronny   Suzie
12      11      12
23      12      5.1

Diviser en plusieurs lignes et ajouter un espace blanc

$ awk '
> FILENAME~1 { a[$0]; next }
> FNR==1 { for(i=1; i<=NF; i++) if($i in a) b[i] }
> { for(j in b) printf("%s\t",$j); print ""}
> ' file{1,2}.txt

Paul    Ronny   Suzie
12      11      12
23      12      5.1
2
kev 8 déc. 2011 à 14:22

Quelque chose comme ça pourrait probablement fonctionner, selon ce que vous voulez.

use strict;
use warnings;

my %names;
open ( my $nh, '<', $name_file_path ) or die "Could not open '$name_file_path'!";
while ( <$nh> ) { 
    m/^\s*(.*?\S)\s*$/ and $names{ $1 } = 1; 
}
close $nh;

my $coln = -1;
open ( my $dh, '<', $data_file_path ) or die "Could not open '$data_file_path'!";

my ( @name_list, @col_list )
my @names = split /\t/, <$dh>;
foreach my $name ( 0..$#names ) {
    next unless exists $names{ $names[ $name ] };
    push @name_list, $name;
    push @col_list, $coln;
}
local $" = "\t";
print "@name_list\n";
print "@{[ split /\t/ ]}[ @col_list ]\n"  while <$dh>;
close $dh;
1
Axeman 8 déc. 2011 à 15:15

Cela pourrait fonctionner pour vous:

 sed '1{s/\t/\n/gp};d' file2 |
 nl |
 grep -f file1 |
 cut -f1 |
 paste -sd, |
 sed 's/ //g;s,.*,cut -f& /tmp/b,' |
 sh

Explication:

  1. Faire pivoter les noms des colonnes
  2. Numéroter les noms des colonnes
  3. Faites correspondre les noms de colonne avec le fichier d'entrée.
  4. Laissez tomber les noms de colonne en conservant les numéros de colonne.
  5. Faites pivoter les numéros de colonne séparés par des ,.
  6. Créez une commande cut à partir de la liste des numéros de colonne séparés par des virgules.
  7. Exécutez la commande cut sur le fichier de données.
1
potong 8 déc. 2011 à 20:50

Vous pouvez utiliser uniquement bash pour le faire:

FIELDS=`head -1 f2.txt | tr "\t" "\n" | nl -ba | grep -f f1.txt | cut -f1 | tr -d " " | tr "\n" ","`; FIELDS=${FIELDS/%,/}
cut -f$FIELDS f2.txt 
Paul    Ronny   Ruby    Suzie
12  11  11  12
23  12  8.9 5.1
2
Sorin 8 déc. 2011 à 14:12

Solution Perl:

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

open my $KEYS, '<', 'file1' or die $!;
my @keys = <$KEYS>;
close $KEYS;
chomp @keys;
my %is_key;
undef @is_key{@keys};

open my $TAB, '<', 'file2' or die $!;
$_ = <$TAB>;
my ($i, @columns);
for (split) {
    push @columns, $i if exists $is_key{$_};
    $i++;
}
do {{
    my @values = split;
    print join("\t", @values[@columns]), "\n";
}} while <$TAB>;
1
choroba 8 déc. 2011 à 14:16
8431917