Perl,使用两个不同的哈希表生成新数据(新哈希)

时间:2012-04-23 07:17:08

标签: perl hashtable information-extraction

我遇到了一个非常复杂的问题(在我看来是一个新手),我不知道如何解决它。我可以想到工作流程而不是脚本。

我的文件A如下所示:教师(标签)Student1(空格)Student2(空格)..

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

当有两个相同的名字时,他们有时会在他们的名字旁边有数字(例如,John1,John2)。如果学生有两名以上的顾问,他们也可能会重叠。

文件B是一个由教师组组成的文件。它看起来很相似,但值是以逗号分隔的。

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

文件B中的趋势是一个键具有多个值,每个值也成为一个键,以便轻松找到谁与谁组合。

我想要的输出是哪些学生可能会根据他们的老师/小组接受类似的教育。所以我希望脚本能够做到以下几点:

  1. 将文件A存储到哈希并关闭
  2. 打开文件B,通过每位老师看他们是否有学生(有些可能没有,实际的名单很大......)。因此,如果我带第一位老师Fiona,它将查看存储文件A哈希表以查看是否存在Fiona。如果有,(在这种情况下,Nicole和Sherry),将它们作为新键散列到新的哈希表中。

    while (<Group>) {
        chomp;
        $data=$_;
        $data=~/^(\S+)\s+(.*)$/;
        $TeacherA=$1;
        $group=$2; 
    
  3. 然后,看看与Fiona(Racheal,Jack)分组的教师组。一次带一个人(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
    

    自从Fiona小组的下一位老师Jack没有任何学生以来,他就不会出现这种结果。如果他有,例如,大卫,结果将是:

    Nicole  Bobby,Dan,Nicole    Fiona   Racheal
    Sherry  Bobby,Dan,Nicole    Fiona   Racheal
    Nicole  David               Fiona   Jack
    Sherry  David               Fiona   Jack
    
  7. 我很抱歉提出这么复杂而具体的问题。我希望通过任何机会做出类似事情的其他人都可以从答案中受益。 非常感谢你的帮助和回复。你是我唯一的帮助来源。

2 个答案:

答案 0 :(得分: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+(.*)$/;这样的正则表达式来获取简单的两列列表的值。使用split operator来做这件事要容易得多。

当您从具有<FILEHANDLE>语法的文件中读取时,您可以将您想要的行的标量放入while循环的条件中,如下所示:

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

在全部大写中写入文件句柄名称也是common

我建议你看看'学习Perl'。哈希和数组的基本概念应该足以发布像这样的任务。希望这会有所帮助。

答案 1 :(得分:1)

我无法想象为什么你会想要这个冗余数据,当你只看文件A以了解谁正在接受类似的教育......但这是一种在perl中做到这一点的方法相同。

$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