我遇到了一个非常复杂的问题(在我看来是一个新手),我不知道如何解决它。我可以想到工作流程而不是脚本。
我的文件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中的趋势是一个键具有多个值,每个值也成为一个键,以便轻松找到谁与谁组合。
我想要的输出是哪些学生可能会根据他们的老师/小组接受类似的教育。所以我希望脚本能够做到以下几点:
打开文件B,通过每位老师看他们是否有学生(有些可能没有,实际的名单很大......)。因此,如果我带第一位老师Fiona,它将查看存储文件A哈希表以查看是否存在Fiona。如果有,(在这种情况下,Nicole和Sherry),将它们作为新键散列到新的哈希表中。
while (<Group>) {
chomp;
$data=$_;
$data=~/^(\S+)\s+(.*)$/;
$TeacherA=$1;
$group=$2;
然后,看看与Fiona(Racheal,Jack)分组的教师组。一次带一个人(Racheal)
if (defined??) {
while ($list=~/(\w+)(.*)/) {
$TeacherB=$1;
$group=$2;
打印学生和教师组。
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
我很抱歉提出这么复杂而具体的问题。我希望通过任何机会做出类似事情的其他人都可以从答案中受益。 非常感谢你的帮助和回复。你是我唯一的帮助来源。
答案 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