use*_*209 0 perl distance text-files
这是我的数据
nodes x y z
1112, 23, 56, 88
2223, 56, 78, 54
3345, 32, 12, 11
4321, 11, 10, 06
5234, 10, 10, 12
6123, 12, 06, 04
Run Code Online (Sandbox Code Playgroud)
现在我想要那些彼此最近的节点.例如:如果节点(1112)和节点(4321)之间的距离小于(令d = 10)节点(1112)和节点(3345)之间的距离(让d = 34)反之亦然,输出应为=
node:1112 and node:4321 are closest
node:6123 and node:3345 are closest.....
Run Code Online (Sandbox Code Playgroud)
我正在使用这样的距离公式:my $ dist = sqrt(($ x- $ x2)*2 +($ y- $ y2)*2 +($ z- $ z2)**2);
i.e:
d=sqrt( (56-23)**2 + (78-56)**2 + (54-88)**2 )
d=sqrt( (32-23)**2 + (12-56)**2 + (11-88)**2 )
d=sqrt( (11-23)**2 + (10-56)**2 + (06-88)**2 )
d=sqrt( (10-23)**2 + (10-56)**2 + (12-88)**2 )....and so on
Run Code Online (Sandbox Code Playgroud)
类似地,对于其他节点及其坐标
d=sqrt( (23-56)**2 + (56-78)**2 + (88-54)**2 )
d=sqrt( (32-56)**2 + (12-78)**2 + (11-54)**2 )
d=sqrt( (11-56)**2 + (10-78)**2 + (06-54)**2 )
d=sqrt( (10-56)**2 + (10-78)**2 + (12-54)**2 )....
Run Code Online (Sandbox Code Playgroud)
我做到了这一点却什么都没有......
use strict;
use warnings;
use Data::Dumper;
open(IN , "<" , "1.txt");
#open(OUT , ">" , "out.txt");
my $node_flag=0;
my %node_hash_1;
my %node_hash_2;
my @node_1;
my @node_2;
my @distance_array;
my $i=0;
foreach my $line(<IN>)
{
if($line=~/^\*node$/i)
{
$node_flag=1;
next;
}
if($node_flag==1)
{
if($line!~/^\*\*/i)
{
my @array=split(",",$line); # or my @array=(split(",",$line))[1,2,3]
my $node_id=shift @array;
$node_hash_1{$node_id}=\@array;
push(@node_1,[@array]);
push(@node_2,[@array]);
foreach my $var1(@node_1)
{
my($x,$y,$z)=@{$var1};
foreach my $var2(@node_2)
{
my($x2,$y2,$z2)=@{$var2};
my $dist = sqrt( ($x-$x2)**2 + ($y-$y2)**2 + ($z-$z2)**2 );
# print $dist;
print"\n";
foreach my $value(@{$node_hash_1{$node_id}})
{
my $vars=join",",@{$node_hash_1{$node_id}};
my @arr=split ",",$vars;
# print $arr[0];
print $vars;
if ($x==$value && $y==$value && $z==$value)
{
push @{$node_hash_1{$node_id}},$dist;
# $node_hash_2{x} = $x;
# $node_hash_2{y} = $y;
# $node_hash_2{z} = $z;
}
}
}
}
}
else
{
$node_flag=0;
}
}
}
#print Dumper(\%node_hash);
#print Dumper(\@distance_array);
#print Dumper(\@node_1);
#print Dumper(\%node_hash_2);
Run Code Online (Sandbox Code Playgroud)
输入行永远不会匹配'*node'所以$node_flag永远不会被设置,所以第二个if被完全跳过,跳过一切.
'nodes'a 's'和来自第一行的开头,我不认为你有正确的.'*',我认为你不明白这/\*/是一种匹配文字明星的方式.我修改了正则表达式来读取m/^nodes\b/,至少设置$ node_flag并让我进入主体.这是事情,但如果您知道文件顶部会出现一定数量的行,并且您不需要这些信息,则可以:
<IN> foreach 1..2;
# or just once if that blank line is just a formatting mistake.
Run Code Online (Sandbox Code Playgroud)
如果要检查标题行:
die 'No Header Line!' unless <IN> =~ m/^nodes\b/;
Run Code Online (Sandbox Code Playgroud)
这样,你不进入循环(while无论如何它应该是一个循环).
您将相同的坐标推入两个数组,表明您过度使用了foreach循环.
此外,做一个笛卡尔比较而收集的数据可以以更好的方式来完成,如果你保持当前的输入值淘汰之列,比较它已经存储在列表中的成员.看起来您最终会将节点#1与节点#1进行比较,因为您拥有的线路数量很多.
虽然如果我真的关心数据,我可能会将它分解为一组类,但我将以下更改作为直接perl行处理器提供:
my ( @node_list, %distance_between, %closest_to );
die 'No Header' unless <IN> =~ m/^nodes\b/;
while ( my $line = <IN> ) {
my ( $name, $x, $y, $z ) = split /\s*,\s*/, $line;
foreach my $comp_node ( @node_list ) {
my ( $name2, $x2, $y2, $z2 ) = @$comp_node;
# distance_between is a needless structure, if
# you don't want to keep the distance.
$distance_between{ $name2 }{ $name }
= $distance_between{ $name }{ $name2 }
= my $dist
= sqrt( ($x-$x2)**2 + ($y-$y2)**2 + ($z-$z2)**2 )
;
my $closest = $closest_to{ $name2 } ||= [ $name, $dist ];
if ( $closest->[1] > $dist ) {
$closest_to{ $name2 } = [ $name, $dist ];
}
$closest = $closest_to{ $name } ||= [ $name2, $dist ];
if ( $closest->[1] > $dist ) {
$closest_to{ $name } = [ $name2, $dist ];
}
}
push @node_list, [ $name, $x, $y, $z ];
}
foreach my $p ( map { [ $_, $closest_to{ $_ }[0] ] } sort keys %closest_to ) {
say "$p->[0]'s closest neighbor is $p->[1]" ;
}
Run Code Online (Sandbox Code Playgroud)