3

私は非常に複雑な問題にぶつかりました (初心者としての私の観点から)、それを解決する方法がわかりません。ワークフローは思いつきますが、スクリプトは思い浮かびません。

次のようなファイル A があります: Teacher (tab) Student1(space)Student2(space)..

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

同じ名前が 2 つある場合 (John1、John2 など)、名前のすぐ横に数字が表示されることがあります。アドバイザーが 2 人以上いる場合は、生徒が重複することもあります。

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

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

ファイル B の傾向は、キーには複数の値があり、各値もキーになり、誰が誰とグループ化されているかを簡単に見つけることができます。

私が望む出力は、教師/グループに基づいて、どの学生が同様の教育を受ける可能性が高いかということです。したがって、スクリプトで次のことを実行したいと思います。

  1. ファイル A をハッシュに格納して閉じる
  2. ファイル B を開き、各教師を調べて、生徒がいるかどうかを確認します (実際のリストは非常に大きいため、そうでない場合もあります..)。したがって、最初の教師であるフィオナを取り上げると、格納されたファイル A ハッシュ テーブルを調べて、フィオナが存在するかどうかを確認します。存在する場合 (この場合はニコールとシェリー)、それぞれを新しいハッシュ テーブルへの新しいキーとしてポップします。

    while (<Group>) {
        chomp;
        $data=$_;
        $data=~/^(\S+)\s+(.*)$/;
        $TeacherA=$1;
        $group=$2; 
    
  3. 次に、Fiona (Racheal、Jack) とグループ化された教師のグループを見てください。一度に1人ずつ連れていく (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
    

    フィオナのグループの次の教師であるジャックには生徒がいなかったため、この結果には含まれていません。たとえば、彼が David だった場合、結果は次のようになります。

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

このような複雑で具体的な質問をして申し訳ありません。ひょっとしてこのようなことをしている他の人が答えから恩恵を受けることを願っています。あなたの助けと返信に感謝します。あなたは私の唯一の助けです。

4

2 に答える 2

1

ファイル A を見るだけで、誰が同様の教育を受けているかを知ることができるのに、なぜこの冗長なデータが必要なのか想像できません。

$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
于 2012-04-23T09:29:49.210 に答える
1

これはデータを見るのにかなり奇妙な方法ですが、私はあなたが試みた方法で動作するようになったと思います. データをそのようにしたい理由を見るのは興味深いでしょう。次回は列見出しを提供するかもしれません。自分が特定の方法で何かを行う理由を知っていると、多くの場合、それを達成する方法を考えるのがずっと簡単になります。

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

my $file_a = qq~Fiona\tNicole Sherry
James\tAlan Nicole
Michelle\tCrystal
Racheal\tBobby Dan Nicole
~;

my $file_b = qq~Fiona\tRacheal,Jack
Michelle\tRacheal
Racheal\tFiona,Michelle
Jack\tFiona
~;

その後、「ファイル」の読み取りに進みます。

# 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";
    }
  }
}

私にとっては、次の出力が得られます。

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

私はすべての値を持っているわけではないので、これはおそらく奇妙です。

とにかく、これにはいくつかのことが言えます。

$data=~/^(\S+)\s+(.*)$/;サンプル コードでは、単純な 2 列のリストの値を取得するためにregex like を使用しました。これを行うには、分割演算子を使用する方がはるかに簡単です。

構文を使用してファイルから読み取る場合、次のように、行をループの条件<FILEHANDLE>に入れるスカラーを配置できます。while

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

また、ファイルハンドル名はすべて大文字で書くのが一般的です。

「Learning Perl」をご覧になることをお勧めします。そこにあるハッシュと配列の基本的な概念は、このようなタスクに取り組むのに十分なはずです。お役に立てれば。

于 2012-04-23T09:26:30.567 に答える