2012-04-23 11 views
3

私は非常に複雑な問題(初心者の私の見解では)にぶつかり、解決方法がわかりません。ワークフローを考えることはできますが、スクリプトは考えられません。2つの異なるハッシュテーブルを使用して新しいデータ(新しいハッシュ)を生成するPerl

私は次のようなファイルA持っている:教師(タブ)STUDENT1(スペース)Student2(スペース)..

Fiona  Nicole Sherry 
James  Alan Nicole 
Michelle Crystal 
Racheal  Bobby Dan Nicole 

の2があるとき、彼らは時々右隣自分の名前に数字を持っています同じ名前(ex、John1、John2)。 2人以上のアドバイザーがいる場合は、重複することもあります。

ファイルBは教師のグループをまとめたファイルです。同様のように見えますが、値はカンマで区切られています。

Fiona  Racheal,Jack 
Michelle Racheal 
Racheal  Fiona,Michelle 
Jack  Fiona 

ファイルBのトレンドは、キーに複数の値があり、各値がキーとなり、誰とグループ化されているのかを簡単に見つけることができます。ハッシュへ

  1. ストアファイルAと:

    私は希望の出力は、生徒が先生に基づいて同様の教育を受ける可能性が高いだろう/ groups.So私は次の操作を実行するスクリプトを希望されています閉じる

  2. ファイルBを開いて、各生徒が生徒を持っているかどうかを確認します(実際のリストはかなり大きくなります)。だから私は最初の教師、フィオナを取る場合、それは格納されているファイルを見て、フィオナがあるかどうかを確認するハッシュテーブル。存在する場合(この場合はNicoleとSherry)、それぞれを新しいキーとして新しいハッシュテーブルにポップします。

    while (<Group>) { 
        chomp; 
        $data=$_; 
        $data=~/^(\S+)\s+(.*)$/; 
        $TeacherA=$1; 
        $group=$2; 
    
  3. 次に、フィオナ(Racheal、ジャック)でグループ化されている先生方のグループを見てください。一人で一人ずつ(Racheal)

    if (defined??) { 
        while ($list=~/(\w+)(.*)/) { 
         $TeacherB=$1; 
         $group=$2; 
    
  4. Rachealの学生のためのファイルAを見てください。
  5. 手順2で作成した学生キーの値(カンマ区切り)として入力します。
  6. 学生 - 学生と教師 - 教師のグループを印刷します。

    Nicole Bobby,Dan,Nicole Fiona Racheal 
    Sherry Bobby,Dan,Nicole Fiona Racheal 
    

    フィオナのグループの次の先生、ジャックは生徒がいないので、彼はこの結果にはないでしょう。彼が持っていた場合、例えば、ダビデは、その結果は次のようになります。

    Nicole Bobby,Dan,Nicole Fiona Racheal 
    Sherry Bobby,Dan,Nicole Fiona Racheal 
    Nicole David    Fiona Jack 
    Sherry David    Fiona Jack 
    

私はこのような複雑な、特定の質問をするためにとても残念です。私はこのような何かをしている他の人が何らかのチャンスで答えを受けることを願っています。 ご協力いただきありがとうございます。あなたは私の唯一の助けの源です。

+0

私は、ファイルBの内容について困惑しているファイルB内のすべての名前が教師に属しているのですか? –

+0

はい、ファイルBは教師に属します。申し訳ありませんが、私がやっていることや初心者であることが奇妙に思えるかもしれませんが、私は手動でやり始めましたが、私が持っているファイルはここで示した単純化されたスナップショットではなく、私は同時に混乱している。 – absolutenewbie

+0

手作業の代わりにperlを使うのは良い考えでした。 Perlはそのようなものには最適です。 – simbabque

答えて

1

これはデータを見るのにはちょっと変わった方法ですが、私が試したやり方でうまくいくと思います。なぜデータをそのようにしたいのか興味深いでしょう。次回に列見出しを提供するかもしれません。あなたが何らかの形で何かをする理由を知ることは、それを実現する方法を考えるのがより簡単になることがよくあります。

これは私がしたことです。混乱しないでください。ファイルAとファイルBの値をスカラーに入れ、それらの値を読み込んだ部分を変更しました。

その後、「ファイル」を読み進めます。

Sherry Bobby,Dan,Nicole Fiona Racheal 
Nicole Bobby,Dan,Nicole Fiona Racheal 
Crystal Bobby,Dan,Nicole Michelle Racheal 
Bobby Crystal Racheal Fiona Michelle 
Nicole Crystal Racheal Fiona Michelle 
Dan Crystal Racheal Fiona Michelle 

これは私がすべての値を持っていないので、おそらく奇妙です:

# 1: Store file A in a hash 
my (%file_a); 
foreach my $a (split /\n/, $file_a) { 
    my @temp = split /\t/, $a; 
    $file_a{$temp[0]} = $temp[1]; 
} 

# 2: Go through file B 
foreach my $b (split /\n/, $file_b) { 
    my @line_b = split /\t/, $b; 
    # Look in stored file A if the teacher is there 
    if (exists $file_a{$line_b[0]}) { 
    my (%new_hash_table, @teachers); 
    # Put all the students of this teacher into a new hash 
    $new_hash_table{$_} = '' foreach split//, $file_a{$line_b[0]}; 

    # 3: Take one of the group of teachers who are grouped with the 
    # current teacher at a time 
    foreach my $teacher (split /,/, $line_b[1]) { 
     if (exists $file_a{$teacher}) { 
     # 4: This teacher from the group has students listen in file A 
     push @teachers, $teacher; # Store the teacher's name for print later 
     foreach (keys %new_hash_table) { 
      # 5: Fill the students as csv for the student keys from step 2 
      $new_hash_table{$_} = join(',', split(/ /, $file_a{$teacher})); 
     } 
     } 
    } 
    foreach my $student (keys %new_hash_table) { 
     # 6: Print...   
     print join("\t", 
     # Student-student relation 
     $student, $new_hash_table{$student}, 
     # Teacher-teacher relation 
     $line_b[0], @teachers); 
     print "\n"; 
    } 
    } 
} 

は私にとって、それは次のような出力を提供します。

とにかく、これにはいくつかのことがあります。

例のコードでは、$data=~/^(\S+)\s+(.*)$/;のような正規表現を使用して、単純な2列のリストの値を取得しました。これを行うにはsplit operatorを使うほうがずっと簡単です。

あなたは<FILEHANDLE>構文を使用してファイルから読み込むときに、あなたがあなたのラインがそうのようなwhileループの状態にに行きたいスカラを置くことができます。

while (my $data = <GROUP>) { 
     chomp $data 

はまた、それはファイルハンドルの名前を書くことcommonですオール・キャップで。

「Perlの学習」をご覧になることをお勧めします。ハッシュと配列の基本的な概念は、このようなタスクを処理するのに十分でなければなりません。お役に立てれば。

+1

Typeglobを使用しないでください。代わりに字句ファイルハンドルを使用してください。 http://stackoverflow.com/questions/3276674/which-one-is-good-practice-a-lexical-filehandle-or-a-typeglobまたはhttp://stackoverflow.com/questions/1479741/why-isを参照してください。 -three-argument-open-calls-with-lexical-filehandles-a-perl-best-practice – dgw

+0

@ simbabque-私の質問に感謝します。私は奇妙に聞こえる。私はちょうどスカラーに私の2つのファイルを変更することについての質問を持っていた。もしこれが素朴な質問だったら私を許してください。しかし、私のファイルサイズが私が例として挙げたよりもはるかに大きいなら、これをやるのが最良の方法でしょうか?そうでない場合は、他に何か提案することができますか? – absolutenewbie

+0

いいえ、そうではありません。実際には、私は怠惰からそれをやったので、ファイルを作成する必要はありませんでした。しかし、上記のプログラムの仕組みは、どこからデータを取得しても同じです。もちろん、生産的なプログラムでは、あなたの入力がプログラムから取り除かれたほうがいいでしょう。それ以外の場合は新しいデータを受け取るたびにプログラムコードを変更する必要があるため、パラメータ(この場合は2つのファイル名)として渡す必要があります。そして、常にperlには複数の方法がありますが、最良の方法はめったにないことを覚えておいてください。 ;-) – simbabque

1

ファイルAを見て、誰が似たような教育を受けているのかを知るには、この冗長なデータが必要な理由を想像することはできませんが、ここではperl all同じ。

$data = {}; 
# pull in students 
open(IN, "students.txt"); 
while(my $line = <IN>) { 
    chomp($line); 
    my ($teacher, @students) = split(/\s+/,$line); 
    $data->{$teacher}->{students} = \@students; 
} 
close IN; 
# pull in teachers 
open(IN, "teachers.txt"); 
while(my $line = <IN>) { 
    chomp($line); 
    my ($teacher, $supporters) = split(/\s+/,$line); 
    my @supporters = split(/,/,$supporters); 
    $data->{$teacher}->{supporters} = \@supporters; 
} 
close IN; 
# make the output 
foreach my $teacher (keys %{$data}){ 
    foreach my $teacher_student (@{$data->{$teacher}->{students}}) { 
    foreach my $supporter (@{$data->{$teacher}->{supporters}}){ 
     my $num_supporter_students = @{$data->{$supporter}->{students}} + 0; 
     if($num_supporter_students) { 

     print "$teacher_student\t" . 
       join(",",@{$data->{$supporter}->{students}}) . 
       "\t$teacher\t$supporter\n"; 
     } 
    } 
    } 
} 

それが返す質問に記載されているデータ上で実行する場合:

Crystal Bobby,Dan,Nicole Michelle Racheal 
Nicole Bobby,Dan,Nicole Fiona Racheal 
Sherry Bobby,Dan,Nicole Fiona Racheal 
Bobby Nicole,Sherry Racheal Fiona 
Bobby Crystal Racheal Michelle 
Dan Nicole,Sherry Racheal Fiona 
Dan Crystal Racheal Michelle 
Nicole Nicole,Sherry Racheal Fiona 
Nicole Crystal Racheal Michelle 
+0

'foreach'の代わりに' for'を使い、 'open(IN、" <"、" filename.txt ")' – gaussblurinc

+0

@ zortacon-まず、私の質問に取り組んでくれてありがとう。私はあなたがそれをやっていた方法を理解していると思います。残念ながら、それは私に 'Matched_student.pl line24での配列逆参照での初期化されていない値の使用'というエラーを出しています。 'match_student.pl line24でさらに初期化されていない値を使用する(+)。'それはまた、私が後にしている完全なリストを私に与えていない。私はそれが最初の試合(フィオナ - ラシェルのペア)を比較していると思う。 – absolutenewbie

+0

エラーは、教師が生徒のテキストファイルから読み込まれている間に生徒が設定されていないことを意味します。リンクを配列に逆参照し、そこに何も見つけません。それはただの警告であって、走りを止めるものではありません。 – zortacon

関連する問題