我遇到了一个非常复杂的问题(以我作为新手的角度),我不知道如何解决这个问题。我能想到工作流,而不是脚本。
我的文件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中的趋势是,一个键有多个值,每个值也成为一个键,可以很容易地找到与谁分组的人。
我想要的结果是,哪些学生可能会根据他们的老师/群体接受类似的教育,所以我希望这个脚本能够做到以下几点:
我很抱歉问了这么复杂而具体的问题。我希望其他正在做这种事情的人能从答案中获益。非常感谢您的帮助和答复。你是我唯一的帮助来源。
发布于 2012-04-23 09:26:30
这是一个相当奇怪的方式来看待数据,但我想我让它的工作方式,你试过。这将是有趣的,看看为什么你希望数据是那样的。下一次也许提供列标题。了解你为什么以某种方式做某事,常常会使你更容易想到实现它的方法,海事组织。
所以我就是这么做的。不要感到困惑,我把你的值从文件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+(.*)$/;
这样的正则表达式来获取一个简单的两列列表的值。使用分裂算子来实现这一点要容易得多。
当您使用<FILEHANDLE>
语法从文件中读取时,可以将希望您的行进入while
循环的标量放入如下所示:
while (my $data = <GROUP>) {
chomp $data
此外,常见还可以用大写格式编写文件句柄名。
我建议您看看‘学习Perl’。其中的散列和数组的基本概念应该足以完成像这样的任务。希望这能有所帮助。
发布于 2012-04-23 09:29:49
我想不出你为什么想要这些多余的数据,而你只需要查看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
https://stackoverflow.com/questions/10276320
复制相似问题