Perl 嵌套while循环以计算多个目的地的距离
好吧,我现在搞砸了。我想创建一个使用严格限制和警告的合适脚本(对我来说仍然是一个挑战;)。但现在我完全迷路了。我看了太多的例子,完全弄糊涂了。我想用lat/lon来计算两点之间的距离。我想我已经用地理信息系统覆盖了那部分:距离。但问题是我试图找到彼此距离在5000米以内的目的地。(如果目的地相同,则跳过)。因此,当它找到一个距离另一个目的地5000m以内的目的地时,我希望它将其放置在第一个文件中的最后一个元素之后 两个输入文件都是相同的,下面是它们的外观。两个文件都有大约45k行Perl 嵌套while循环以计算多个目的地的距离,perl,geolocation,while-loop,Perl,Geolocation,While Loop,好吧,我现在搞砸了。我想创建一个使用严格限制和警告的合适脚本(对我来说仍然是一个挑战;)。但现在我完全迷路了。我看了太多的例子,完全弄糊涂了。我想用lat/lon来计算两点之间的距离。我想我已经用地理信息系统覆盖了那部分:距离。但问题是我试图找到彼此距离在5000米以内的目的地。(如果目的地相同,则跳过)。因此,当它找到一个距离另一个目的地5000m以内的目的地时,我希望它将其放置在第一个文件中的最后一个元素之后 两个输入文件都是相同的,下面是它们的外观。两个文件都有大约45k行 Europe;
Europe;3;France;23;Parijs;42545;48,856555;2,350976
Europe;3;France;23;Parisot;84459;44,264381;1,857827
Europe;3;France;23;Parlan;11337;44,828976;2,172435
Europe;3;France;23;Parnac;35670;46,4533;1,4425
Europe;3;France;23;Parnans;22065;45,1097;5,1456
假设这两个目的地中有两个彼此很近,我尝试这样输出:
Europe;3;France;23;Parijs;42545;48,856555;2,350976;Parlan;11337;200
Europe;3;France;23;Parisot;84459;44,264381;1,857827;
Europe;3;France;23;Parlan;11337;44,828976;2,172435;
Europe;3;France;23;Parnac;35670;46,4533;1,4425;Parisot;84459;2000;Parnans;22065;350
Europe;3;France;23;Parnans;22065;45,1097;5,1456;
当然,实际结果将匹配2个以上。在输出文件中,添加匹配的目的地、目的地id和计算的距离。可能每个目的地都有多个匹配项。Pff这真的很难解释哈哈。正如我所说的,我使用了strict&warnings,并将错误缩小到最小,但仍然没有完全消除。以下是错误:
Global symbol "$infile1" requires explicit package name at E:\etc.pl line 17.
Execution of E:\etc.pl aborted due to compilation errors.
这是我目前掌握的代码。我的声明也不是正面或反面的
有人能帮我吗?(也许这不是最有效的方法,但现在它帮助我一步一步地理解perl)
使用严格;
使用警告;
使用GIS::Distance::Lite qw(距离);
my$inputfile1=shift | | die“给出输入!\n”;
my$inputfile2=shift | | die“提供更多输入!\n”;
my$outputfile=shift | | die“给出输出!\n”;
打开我的$INFILE1、$lat2、$lon2);#Afstand berekenen tussen Latron1和Latron2
打印“7.$distance\n”;
我的$afstand=sprintf(%.4f',$distance);
打印“8.$afstand\n”;
如果($afstand<$maxdist&&$elements[4]!=$loopelements[4]){
推送(@elements、$afstand、$loopelements[4]、$loopelements[5]);
打印“9.$afstand\n”;
}否则{
下一个
}
}
打印$OUTFILE联接(“;”,@elements),“\n”;
}
关闭(1美元);
关闭(2美元);
关闭($OUTFILE);
你已经做得很好了。让我们看一下你的错误信息。< /P>
全局符号“$infile1”要求在E:\etc.pl第17行显示包名
这个很简单。在Perl中,它们都区分大小写。在顶部,创建一个变量$INFILE1
。稍后我将进一步讨论词汇
open my $INFILE1, '<', $inputfile1 or die "In use/Not found :$!\n";
您尚未声明该变量(使用my
),因此它会抛出此错误。但这还不是全部
我相信你是在试图从那个文件句柄读取数据。但这是行不通的。我将分步骤解释这一点。
-事实上,您已经构建了一个无限循环,但您还没有意识到它
while ( my @infile1 ){
此while
循环不会停止。曾经带有my
的@infile1
声明总是返回一个真值,因为它总是有效的。所以你永远不会打破这个循环
- 我猜你是在逐行阅读文件。让我们看看我们如何做到这一点:
while (my $infile1 = <$INFILE1> ){ my @elements = split(";",$infile1);
- 接下来是
行。这看起来像是要从第一个文件的每一行开始读取第二个文件。这在某种程度上是有道理的,但效率很低。我以后再谈。不过,您确实需要更改seek
。您不必在此处创建新变量。此外,请使用正确的名称:my
seek $INFILE2, 0, 0;
- 让我们改为修复第二个
循环:while
别担心,这里没什么问题。我只想指出,while (my $infile2 = <$INFILE2>){ chomp $infile2; my @loopelements = split(";",$infile2);
是另一种写逗号的方法(=>
)。它有时被称为胖逗号,这样更容易阅读,例如,散列赋值,
- 在第50行,你已经知道了距离
读起来好多了,不是吗if (($afstand < $maxdist) and (!($elements[4] == $loopelements[4]))){
- 在第58行,您加入数组
并将其分配给自身。这很奇怪。它将用一个只有一个元素的新数组替换该数组——连接的字符串。让我们把那条线留到下一颗子弹,然后再看@elements
- 在第59行,您有一个
语句,但您现在使用的是一个从未创建过的全局文件句柄print
。相反,您需要从顶部使用词法文件句柄,OUTFILE
。如果我们现在将上面一行中的$OUTFILE
直接添加到print语句中,并在末尾添加一个join
新行字符,则该行变为:\n
print $OUTFILE join(";",@elements), "\n";
- 现在只剩下最后一部分了:您需要关闭文件句柄,但还是要使用全局句柄。使用你的词汇:
close($INFILE1); close($INFILE2); close($OUTFILE);
use strict;
use warnings;
use GIS::Distance::Lite qw(distance);
my $inputfile1 = shift || die "Give input!\n";
my $inputfile2 = shift || die "Give more input!\n";
my $outputfile = shift || die "Give output!\n";
open my $INFILE1, '<', $inputfile1 or die "In use/Not found :$!\n";
open my $INFILE2, '<', $inputfile2 or die "In use/Not found :$!\n";
open my $OUTFILE, '>', $outputfile or die "In use/Not found :$!\n";
my $maxdist = 5000;
my $mindist = 0.0001;
while (my $infile1 = <$INFILE1> ){
chomp $infile1;
my @elements = split(";",$infile1);
my $lat1 = $elements[6];
my $lon1 = $elements[7];
$lat1 =~ s/,/./g;
$lon1 =~ s/,/./g;
print "1. $lat1\n";
print "2. $lon1\n";
seek $INFILE2, 0, 0;
while ( my $infile2 = <$INFILE2> ){
chomp $infile2;
my @loopelements = split(";",$infile2);
my $lat2 = $loopelements[6];
my $lon2 = $loopelements[7];
$lat2 =~ s/,/./g;
$lon2 =~ s/,/./g;
print "3. $lat1\n";
print "4. $lon1\n";
my $distance = distance($lat1, $lon1 => $lat2, $lon2); # Afstand berekenen tussen latlon1 and latlon2
print "5. $distance\n";
my $afstand = sprintf("%.4f",$distance);
print "6. $afstand\n";
if ($afstand < $maxdist && $elements[4] ne $loopelements[4]){
push (@elements, $afstand,$loopelements[4],$loopelements[5]);
print "7. $afstand\n";
} else {
next;
}
}
print $OUTFILE join(";",@elements), "\n";
}
close($INFILE1);
close($INFILE2);
close($OUTFILE);
file2.csv:
我将对此添加建议。我认为
$elements[4]
是城市名称,因此他需要使用ne
而不是=代码>。我仍在修复故障。我马上就谈到那件事。谢谢@cjmI稍后会添加其他内容。@simbabque哇,谢谢你的解释!这很有帮助。这个我真的可以用。。我特别感谢你解释为什么它不起作用!对不起,我没有更详细的,谢谢你,哈哈。我马上就去!
my $distance = distance($lat1, $lon1 => $lat2, $lon2);
if (($afstand < $maxdist) and (!($elements[4] == $loopelements[4]))){
if ($afstand < $maxdist && $elements[4] ne $loopelements[4]){
print $OUTFILE join(";",@elements), "\n";
close($INFILE1);
close($INFILE2);
close($OUTFILE);
use strict;
use warnings;
use GIS::Distance::Lite qw(distance);
my $inputfile1 = shift || die "Give input!\n";
my $inputfile2 = shift || die "Give more input!\n";
my $outputfile = shift || die "Give output!\n";
open my $INFILE1, '<', $inputfile1 or die "In use/Not found :$!\n";
open my $INFILE2, '<', $inputfile2 or die "In use/Not found :$!\n";
open my $OUTFILE, '>', $outputfile or die "In use/Not found :$!\n";
my $maxdist = 5000;
my $mindist = 0.0001;
while (my $infile1 = <$INFILE1> ){
chomp $infile1;
my @elements = split(";",$infile1);
my $lat1 = $elements[6];
my $lon1 = $elements[7];
$lat1 =~ s/,/./g;
$lon1 =~ s/,/./g;
print "1. $lat1\n";
print "2. $lon1\n";
seek $INFILE2, 0, 0;
while ( my $infile2 = <$INFILE2> ){
chomp $infile2;
my @loopelements = split(";",$infile2);
my $lat2 = $loopelements[6];
my $lon2 = $loopelements[7];
$lat2 =~ s/,/./g;
$lon2 =~ s/,/./g;
print "3. $lat1\n";
print "4. $lon1\n";
my $distance = distance($lat1, $lon1 => $lat2, $lon2); # Afstand berekenen tussen latlon1 and latlon2
print "5. $distance\n";
my $afstand = sprintf("%.4f",$distance);
print "6. $afstand\n";
if ($afstand < $maxdist && $elements[4] ne $loopelements[4]){
push (@elements, $afstand,$loopelements[4],$loopelements[5]);
print "7. $afstand\n";
} else {
next;
}
}
print $OUTFILE join(";",@elements), "\n";
}
close($INFILE1);
close($INFILE2);
close($OUTFILE);
use strict;
use warnings;
use GIS::Distance::Lite qw(distance);
use feature qw(say);
my $inputfile1 = shift || die "first file missing";
my $inputfile2 = shift || die "second file missing";
my $outputfile = shift || die "output file missing!";
# Read the second file first
my @file2; # save the lines of INFILE2 as array refs
open my $INFILE2, '<', $inputfile2 or die "In use/Not found :$!";
while ( my $infile2 = <$INFILE2> ){
chomp $infile2;
my @loopelements = split(/;/, $infile2);
$loopelements[6] =~ y/,/./;
$loopelements[7] =~ y/,/./;
push @file2, \@loopelements;
}
close($INFILE2);
open my $INFILE1, '<', $inputfile1 or die "In use/Not found :$!";
open my $OUTFILE, '>', $outputfile or die "In use/Not found :$!";
my $maxdist = 5000;
my $mindist = 0.0001;
while (my $infile1 = <$INFILE1> ){
chomp $infile1;
my @elements = split(";",$infile1);
my $lat1 = $elements[6];
my $lon1 = $elements[7];
$lat1 =~ y/,/./;
$lon1 =~ y/,/./;
say "1. $lat1";
say "2. $lon1";
FILE2: foreach my $loopelements ( @file2 ){
my ($lat2, $lon2) = @$loopelements[6, 7];
say "3. $lat2";
say "4. $lon2";
my $distance = distance($lat1, $lon1 => $lat2, $lon2); # Afstand berekenen tussen latlon1 and latlon2
say "5. $distance";
my $afstand = sprintf("%.4f",$distance);
say "6. $afstand";
if ($afstand < $maxdist && $elements[4] ne $$loopelements[4]){
push (@elements, $afstand, $$loopelements[4], $$loopelements[5]);
say "7. $afstand";
} else {
next FILE2;
}
}
say $OUTFILE join(";",@elements);
}
close($INFILE1);
close($OUTFILE);
Europe;3;France;23;Parijs;42545;48,856555;2,350976
Europe;3;France;23;Parisot;84459;44,264381;1,857827
Europe;3;France;23;Parlan;11337;44,828976;2,172435
Europe;3;France;23;Parnac;35670;46,4533;1,4425
Europe;3;France;23;Parnans;22065;45,1097;5,1456
Europe;3;France;23;Parlan;11337;44,828976;2,172435
Europe;3;France;23;Parnac;35670;46,4533;1,4425
Europe;3;France;23;Parnans;22065;45,1097;5,1456
Europe;3;France;23;Parijs;42545;48,856555;2,350976
Europe;3;France;23;Parisot;84459;44,264381;1,857827