Perl 嵌套while循环以计算多个目的地的距离

Perl 嵌套while循环以计算多个目的地的距离,perl,geolocation,while-loop,Perl,Geolocation,While Loop,好吧,我现在搞砸了。我想创建一个使用严格限制和警告的合适脚本(对我来说仍然是一个挑战;)。但现在我完全迷路了。我看了太多的例子,完全弄糊涂了。我想用lat/lon来计算两点之间的距离。我想我已经用地理信息系统覆盖了那部分:距离。但问题是我试图找到彼此距离在5000米以内的目的地。(如果目的地相同,则跳过)。因此,当它找到一个距离另一个目的地5000m以内的目的地时,我希望它将其放置在第一个文件中的最后一个元素之后 两个输入文件都是相同的,下面是它们的外观。两个文件都有大约45k行 Europe;

好吧,我现在搞砸了。我想创建一个使用严格限制和警告的合适脚本(对我来说仍然是一个挑战;)。但现在我完全迷路了。我看了太多的例子,完全弄糊涂了。我想用lat/lon来计算两点之间的距离。我想我已经用地理信息系统覆盖了那部分:距离。但问题是我试图找到彼此距离在5000米以内的目的地。(如果目的地相同,则跳过)。因此,当它找到一个距离另一个目的地5000m以内的目的地时,我希望它将其放置在第一个文件中的最后一个元素之后

两个输入文件都是相同的,下面是它们的外观。两个文件都有大约45k行

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
    。如果我们现在将上面一行中的
    join
    直接添加到print语句中,并在末尾添加一个
    \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