0

私はperlを初めて使用し、特定の列を取得するための配列のハッシュの使用について質問があります。私のコードは次のとおりです。

my %hash = ( name1 => ['A', 'A', 'B', 'A', 'A', 'B'],
             name2 => ['A', 'A', 'D', 'A', 'A', 'B'],
             name3 => ['A', 'A', 'B', 'A', 'A', 'C'],
             );

#the values of %hash are returned as arrays not as string (as I want)

foreach my $name (sort keys %hash ) {
    print "$name: ";
    print "$hash{$name}[2]\n";
}

for (my $i=0; $i<$length; $i++) {
        my $diff = "no";
        my $letter = '';
        foreach $name (sort keys %hash) {
            if (defined $hash{$name}[$i]) {
                if ($hash{$name}[$i] =~ /[ABCD]/) {
                    $letter = $hash{$name}[$i];
                }
                elsif ($hash{$name}[$i] ne $letter) { 
                    $diff = "yes";
                }
            }
            if ( $diff eq "yes" ) {
                foreach $name (sort keys %hash) {
                    if (defined $hash{$name}[$i]) { $newhash{$name} .= $hash{$name}[$i]; }  
                }
            }
        }
    }
    foreach $name (sort keys %newhash ) {
        print "$name: $newhash{$name} \n";
    }

このプログラムの出力は、変数列のみを持つ新しいハッシュのようなものにしたいと思います。

my %newhash = ( name1 => 'BB',
            name2 => 'DB',
            name3 => 'BC',
              );

ただし、次のメッセージのみが表示されます。test_hash.plの31行目の文字列neで初期化されていない値$letterを使用しています。

誰かがこれについてアイデアを持っていますか?乾杯

編集:

この質問にご協力いただきありがとうございます。

私は自分の投稿を編集して、frezik、Dan1111、Jeanの提案を確認しました。そうです、今は警告はありませんが、printステートメントからも出力を取得できず、これについての手がかりもありません...

@TLP:わかりました。順序を指定せずに、ランダムな列のセットを生成するだけです。私が本当に望んでいるのは、文字がどのように変化するかです。つまり、同じ配列インデックス(ハッシュに格納されている)に対して文字が同じである場合はそれらを破棄しますが、キー間で文字が異なる場合はそのインデックスを格納します新しいハッシュの列。

乾杯。

4

6 に答える 6

2

これにより、文字 A、B、C、または D のいずれかに一致させたいと仮定します。

if ($hash{$name}[$i] =~ /ABCD/)

ただし、書かれているように、正確な文字列「ABCD」と一致します。必要なものには文字クラスが必要です。

if ($hash{$name}[$i] =~ /[ABCD]/)

ただし、他のロジックの問題もあり、$letter設定前と比較することができます。空に設定する(Jeanが提案したように)のは、役立つ簡単なオプションです。

別の問題はここにあります:

print "$name: @{ $newhash{$name} }\n";

%newhashは配列のハッシュではないため、配列の逆参照を削除する必要があります。

print "$name: $newhash{$name} \n";
于 2012-10-17T14:58:22.163 に答える
2

この代替ソリューションに興味があるかもしれません

use strict;
use warnings;

my %hash = (
  name1 => ['A', 'A', 'B', 'A', 'A', 'B'],
  name2 => ['A', 'A', 'D', 'A', 'A', 'B'],
  name3 => ['A', 'A', 'B', 'A', 'A', 'C'],
);

my @columns;

for my $list (values %hash) {
  $columns[$_]{$list->[$_]}++ for 0 .. $#$list;
}

my %newhash = %hash;

for my $list (values %newhash) {
  $list = join '', map $list->[$_], grep keys %{$columns[$_]} > 1, 0 .. $#$list;
}

use Data::Dump;
dd \%newhash;

出力

{ name1 => "BB", name2 => "DB", name3 => "BC" }
于 2012-10-17T20:12:33.207 に答える
1
if ($hash{$name}[$i] =~ /ABCD/) {

上記の正規表現は、__ABCD__またはのような文字列と一致しますABCD1234が、単独のAまたはB。これらの文字のいずれかと一致させたいと思われるかもしれません。正規表現を固定することもお勧めします。

if ($hash{$name}[$i] =~ /\A [ABCD] \z/x) {

(/ xオプションは、空白が無視されることを意味します。これにより、正規表現が少し読みやすくなります。)

$i == 2上記の例では、内側のループがたまたまキーを押したとき、name1またはname3最初にヒットしたときにも警告が表示されます。正規表現が一致しないため、は初期化されないままになりますT$letter

于 2012-10-17T14:57:24.260 に答える
1

スカラー$letterが定義されていません。これを追加して、警告を取り除きます。

my $letter='';
于 2012-10-17T14:54:54.980 に答える
1

一文字一文字確認するのは間違いだと思います。すべての文字を集めて一度に確認する方が簡単なようです。モジュールのList::MoreUtilsuniq 関数は、文字が異なるかどうかをすばやく判断し、結果のハッシュに簡単に転置できます。

use strict;
use warnings;
use Data::Dumper;
use List::MoreUtils qw(uniq);

my %hash = ( name1 => ['A', 'A', 'B', 'A', 'A', 'B'],
             name2 => ['A', 'A', 'D', 'A', 'A', 'B'],
             name3 => ['A', 'A', 'B', 'A', 'A', 'C'],
);
my @keys = keys %hash;
my $len = $#{ $hash{$keys[0]} };   # max index
my %new;

for my $i (0 .. $len) {
    my @col;
    for my $key (@keys) {
        push @col, $hash{$key}[$i];
    }
    if (uniq(@col) != 1) {     # check for variation
        for (0 .. $#col) {
            $new{$keys[$_]} .= $col[$_];
        }
    }
}
print Dumper \%new;

出力:

$VAR1 = {
          'name2' => 'DB',
          'name1' => 'BB',
          'name3' => 'BC'
        };
于 2012-10-17T15:55:37.483 に答える
0

偉大な。この質問にご協力いただきありがとうございます。

TLP の提案に基づいてコードを試してみたところ、問題なく動作しました。私は比較的 perl に慣れていないので、このコードはボロディンのコードよりも理解しやすいと思いました。私がしたことは:

#!/usr/bin/perl
use strict;
use warnings;
use List::MoreUtils qw(uniq);

my %hash = ( name1 => ['A', 'A', 'T', 'A', 'A', 'T', 'N', 'd', 'd', 'D', 'C', 'T', 'T', 'T'],
         name2 => ['A', 'A', 'D', 'A', 'A', 'T', 'A', 'd', 'a', 'd', 'd', 'T', 'T', 'C'],
         name3 => ['A', 'A', 'T', 'A', 'A', 'C', 'A', 'd', 'd', 'D', 'C', 'T', 'C', 'T'],
);
my @keys = keys %hash;
my $len = $#{ $hash{$keys[0]} };   # max index
my %new;

for (my $i=0; $i<$length; $i++) {
    my @col;
    for my $key (@keys) {
       if ($hash{$key}[$i] =~ /[ABCDT]/) {     #added a pattern match
            push @col, $hash{$key}[$i];
       }
    }
    if (uniq(@col) != 1) {     # check for variation
        for (0 .. $#col) {
            $new{$keys[$_]} .= $col[$_];
        }
    }
}
foreach my $key (sort keys %new ) {
    print "$key: $new{$key}\n";
}

ただし、uniq 関数 (if (uniq(@col) == 1)) をいじっていると、出力に少しバグがあることに気付きました。

name1: AAAAADCT
name2: AAAAADCT
name3: AAAAT

キー => 値の初期順序が保持されていないようです。誰もこれについてのヒントを持っていますか?

乾杯。

于 2012-10-18T09:43:01.617 に答える