-3

テスト.txt

name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari
busi_db

OUT.txt

name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari     1  2  0  7
busi_db  1  6  3  8

TEST.txt に示すようなファイルがあり、値を持たないキーはほとんどありません。値を持たないキーを一致させ、一致したキーと同じ値を入れたいです。サンプル出力は次のとおりです。

編集:異なるファイルで値のあるキーと値のないキーを分離し、それらのファイルを余分な「i」と比較して値を追加する、より長い手順を試みました。この手順を使用しても目的の出力が得られません

4

3 に答える 3

1

このプログラムは、あなたが必要とすることを行うようです。コマンドラインのパラメーターとしてソースデータファイルが必要です

use strict;
use warnings;

<>;

my %data;
my @keys;

while (<>) {
  my ($key, @values) = split;
  if (@values) {
    $data{$key} = \@values;
    push @keys, $key;
  }
  else {
    (my $newkey = $key) =~ s/i(?![a-z])//i;
    my $values = $data{$newkey};
    $data{$key} = [ @$values ];
    push @keys, $key;
  }
}

my $format = "%-7s%3s%3s%3s%3s\n";
printf $format, qw/ name a  b  c  d /;
for my $key (@keys) {
  printf $format, $key, @{ $data{$key} };
}

出力

name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari     1  2  0  7
busi_db  1  6  3  8
于 2012-08-17T12:42:05.163 に答える
0

まず、データをPerlに取り込みましょう。ファイルを開き、最初の空白で分割されたハッシュに読み込みます。プログラムに違いがないため、、、、またはを別々のデータaに分割する必要はありません。bcd

 use strict;
 use warnings;
 use autodie;

 open INPUT, "<", "TEST.txt";
 my %array;
 while my $line (<INPUT>) {
    chomp $line;
    my ($key, $data) = split /\s+/, $line, 2;
    $array{$key} = $value;
 }

これにより、次のようになります。

$array{car} = "1   2   0   7";
$array{tram} = "7   8   9   5";
$array{bus_db} = "1   6   3   8";
$array{cari} = "";
$array{busi_db} = "";

さて、あなたが説明していないことがあります:null配列メンバーが非null配列メンバーと一致するかどうかをどうやって知るのですか。cari それが一致 carしていることをどうやって知ることができbusi_db ます bus_dbか?それはi最後に追加されていますが、可能なdb接尾辞の前ですか?私たちが知っておくべき他のことはありますか?

あなたがそれを理解したら、それらを一致させることは非常に簡単です:

$array{busi_db} = $array{bus_db};

次に、それらを印刷するだけです。

 # Go through array and make "null" members match
 while my $key (sort keys %array) {
    if (not $array{$key}) { #Ah! a null array member!
        $matching_key = find_matching_key($key);
        $array{$key} = $array{$matching_key};
    }
 }

# Print them out
while my $key (sort keys %array) {
    print "$key = $array{$key}\n";
}

sub find_matching_key {
   # Here be dragons....
}

問題はそのfind_matching_keyサブルーチンです。2つの別々のキーが一致する理由を理解し、詳細を入力します。

ちなみに、サンプルデータによると、nullメンバーはnull以外のメンバーの後に来ます。これが常に真の条件である場合、読み取りループをマージループから分離する必要はありません。残念ながら、あなたはこれが本当かどうかを言いませんでした。

また、配列を読み込まれたのと同じ順序で出力する必要があるかどうかを指定しませんでした。キーのリストを保持し、それらを順番に保持することもできました。ロジックが複雑になるので、指定しませんでした。


あなたの質問のランクが低く、人々がそれを締めくくりとしてマークしているという事実に注意してください。これは、基本的に「この問題があります。解決してください」と言ったためです。また、解決策についても十分な詳細を提供していませんでした。私が言ったように、あなたは一致するキーについて話しましたが、あなたが何を意味するのかを特定しませんでした。

于 2012-08-17T13:59:06.310 に答える
0

これが解決策です。これは、空のキーがすべて「i」または「i_db」で終わり、塗りつぶされたキーを取得するには i を削除する必要があることを前提としています。そうでない場合は、$other_key =~ s/i(?=(_db)?$)//g;探しているものに一致するように行を変更する必要があります。また、ファイル I/O はあなたに任せておきます。

use strict; use warnings;

my $header = <DATA>;
#throw away the first field name, as it will be used as the hash key
my (undef,@fields) = (split /\s+/, $header);
my %hash;

#read in the file.
while (<DATA>)
{
    my @row = split /\s+/;
    for (0..$#fields)
    {
        $hash{$row[0]}{$fields[$_]} = $row[$_+1];
    } 
}

#find cases that don't have data and fill them in.
foreach my $line (keys %hash)
{
    foreach (keys %{$hash{$line}})
    {
        unless (defined $hash{$line}{$_})
        {
            my $other_key = $line;
            #Uses a lookahead assertion to match but not delete "_db"
            $other_key =~ s/i(?=(_db)?$)//g;
            if (defined $hash{$other_key}{$_})
            {
                $hash{$line}{$_} = $hash{$other_key}{$_}
            }
        }
    }
}

#Print the output.
print $header;
foreach (keys %hash)
{
    #Uses a hash slice to get all of the values at once.
    print join (" ",$_, @{$hash{$_}}{@fields})."\n";    
}

__END__
name     a  b  c  d
car      1  2  0  7
tram     7  8  9  5
bus_db   1  6  3  8
cari
busi_db
于 2012-08-17T10:29:25.240 に答える