извлечение конкретных данных из таблицы - PullRequest
1 голос
/ 08 декабря 2011

У меня есть таблица, которая выглядит следующим образом (разделены табуляцией):

Ron  Rob  rock bammy
m    f   m  f
florida  Atlanta  florida texas 

Эта таблица имеет порядок 5 * 512 и на основе данных строки 3 я хочу извлечь значения в строке1. например: я хочу иметь имена всех людей, живущих во Флориде и Техасе, в таблице из 2 столбцов и n строк.

Florida  Ron
Florida  Rock
Texas BAmmy

и т. Д.

любые предложения для лайнеров bash или PERL ...

Заранее спасибо.

Ответы [ 5 ]

1 голос
/ 08 декабря 2011

Еще одно решение Perl:

perl -ane 'push@c,@F}{print grep{/^(florida|atlanta)\t/i}map{"$c[$_+$#c/3*2+1]\t$c[$_]\n"}0..$#c/3'

Или как скрипт

#!/usr/bin/perl

use strict;
use warnings;

my (@data, @rows);

push @data, split/\s+/ while (<>);

for (0 .. $#data/3) {
    my $name = $data[$_];
    my $location = $data[$_+$#data/3*2+1];
    push @rows, "$location\t$name\n" if $location =~ /^(florida|atlanta)$/i;
}

print join("", @rows);

с условием if внутри цикла вместо отдельного grep.

Мой подход состоит в том, чтобы объединить все три строки в один массив и использовать for (0 .. $#data/3) для циклического перебора индексов, соответствующих именам из первой строки, и получить местоположение из соответствующего столбца с помощью $data[$_+$#data/3*2+1].

1 голос
/ 08 декабря 2011
awk 'NR==1{for(i=1;i<=NF;i++)n[i]=$i}; NR==3{for(i=1;i<=NF;i++){if($i~/florida|texas/)print $i"\t"n[i];}}' yourFile

см. Тест ниже:

kent$  echo "Ron Rob rock bammy
m f m f
florida Atlanta florida texas"|awk 'NR==1{for(i=1;i<=NF;i++)n[i]=$i}; NR==3{for(i=1;i<=NF;i++){if($i~/florida|texas/)print $i"\t"n[i];}}'

выход

florida Ron
florida rock
texas   bammy

РЕДАКТИРОВАТЬ

kent$  echo "Ron  Rob  rock bammy
m    f   m  f
florida(8)  Atlanta  florida(8) texas(2;7)"|awk 'NR==1{for(i=1;i<=NF;i++)n[i]=$i}; NR==3{for(i=1;i<=NF;i++){if($i~/florida\(8\)|texas\(2;7\)/)print $i"\t"n[i];}}'

вывод:

florida(8)      Ron
florida(8)      rock
texas(2;7)      bammy
0 голосов
/ 08 декабря 2011

Похоже, это работа для Text :: CSV_XS .Это не хорошая идея разбивать на пробелы, как многие полагают, поскольку это не удастся ни для чего, кроме упрощенных данных.*

use strict;
use warnings;
use Text::CSV_XS;

my $csv = Text::CSV_XS->new( {
        sep_char    => "\t",
        binary      => 1,
    });

# get array refs to each row, with appropriate name
# For larger data sets, using an array to hold the array refs would be better
my $name       = $csv->getline(*DATA);
my $gender     = $csv->getline(*DATA);
my $city       = $csv->getline(*DATA);

for (keys @$city) {   # lists the column numbers
    if ($city->[$_] =~ /florida|texas/i) {
        print "$city->[$_]\t$name->[$_]\n";
    }
}

__DATA__
Ron Rob rock    bammy
m   f   m   f
florida Atlanta florida texas

Вывод:

florida Ron
florida rock
texas   bammy
0 голосов
/ 08 декабря 2011
#!/usr/bin/env perl
use strict;
use warnings;

my $pat = shift;

sub interleave($$){
    my ($foo,$bar) = @_;
    return map { ( $_ , shift @{$bar} ) } @{$foo};
}

my $n=0;
my(@p,%h);
while(<>){
    chomp;
    if($n%3==0){
            @p = split /\t/, $_;
    } elsif($n%3==2){
            my @l = split /\t/, $_;
            my %kv = interleave(\@p, \@l);
            foreach my $k (keys %kv){
                    push(@{$h{$kv{$k}}}, $k);
            }
    }
    $n++;
}

foreach my $loc (keys %h){
    if(!defined $pat || $loc =~ /$pat/i){
            foreach my $name (@{$h{$loc}}){
                    print ucfirst($loc), "\t", ucfirst($name), "\n";
            }
    }
}

А потом назовите это

perl extract.pl 'texas|florida' < data

Форма "Oneliner":

perl -ne 'BEGIN{$p=shift||"^";}chomp;if($n++%3!=1){unless(@p){@p=split/\t/,$_;next;}my %kv = map { ( $_ , shift @p ) } split(/\t/, $_);map { push(@{$h{$_}}, $kv{$_}); } keys %kv;}END{map{for my$nm(@{$h{$_}}){print ucfirst($_),"\t",ucfirst($nm),"\n";}}grep{/$p/i}keys%h;}' 'florida|texas' < data
0 голосов
/ 08 декабря 2011

Вот решение Perl, которое работает, но оно немного более замысловатое, чем хотелось бы. Вам, вероятно, было бы лучше поместить эти данные в базу данных.

#!/usr/bin/env perl

use strict;
use warnings;
use 5.010;

my %rows = (
  name => 1,
  location => 3,
);

my %location = map { $_ => 1 } qw[florida texas];

my @names;

while (<DATA>) {
  next unless grep { $_ == $. } values %rows;

  chomp;

  if ($. == $rows{name}) {
    @names = split;
  }

  if ($. == $rows{location}) {
    my @locs = split;

    for my $x (0 .. $#locs) {
      if ($location{lc $locs[$x]}) {
        say ucfirst $locs[$x]. "\t$names[$x]";
      }
    }
    last;
  }
}

__END__
Ron     Rob     rock    bammy
m       f       m       f
florida         Atlanta florida texas
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...