0

これは私のデータです

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

ここで、互いに最も近いノードが必要です。例: ノード (1112) とノード (4321) の間の距離がノード (1112) とノード (3345) の間の距離よりも小さい場合 (let d=10) (let d=34) およびその逆は、出力が次のようになるはずです =

     node:1112 and node:4321 are closest
     node:6123 and node:3345 are closest.....

私は次のような距離式を使用しています: 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

他のノードとその座標についても同様

 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 )....

私はこれをやったが何も得られなかった......

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);
4

2 に答える 2

5

入力行は決して一致しない'*node'ため$node_flag、設定されることはなく、2 番目の if は完全にスキップされ、すべてがスキップされます。

  • 'nodes'最初の行の先頭に and が付いているので's'、正しく持っていないと思います。
  • また、あなたの入力にはリテラルが表示されないため、それが リテラルの星に一致する方法である'*'ことを理解していないと思います./\*/

正規表現を read に修正しましたm/^nodes\b/。これにより、少なくとも $node_flag が設定され、本体に入ります。設定された行数がファイルの先頭に表示されることがわかっていて、その情報が必要ない場合は、次のようにします。

<IN> foreach 1..2; 
# or just once if that blank line is just a formatting mistake.

ヘッダー行を確認したい場合:

die 'No Header Line!' unless <IN> =~ m/^nodes\b/;

そうすれば、ループに入ることはありません (とにかく、ループであるべきwhileです)。

  • 同じ座標を 2 つの配列に押し込んでいることは、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]" ;
}
于 2012-08-09T16:08:48.033 に答える
2
#!/usr/bin/perl

use strict;
use warnings;

my (@data, @temp, @result);

sub calc {
    my ($a, $b) = @_;
    my $dat = 0;
    $dat += ($a->[$_] - $b->[$_]) ** 2 for (1..3);
    return sqrt $dat;
}

while (<DATA>) {
    push @data, [split /,?\s+/];
}

for my $x (@data) {
    for my $y (@data) {
        push @temp, [calc($x, $y), $x, $y] if ($x->[0] > $y->[0]);
    }
}

@result = sort { $a->[0] <=> $b->[0]; } @temp;

for (@result) {
    print "[", join(', ', @{$_->[1]}), "], [", join(', ', @{$_->[2]}),
        "] => $_->[0]\n";
}

__DATA__
1112,         23,       56,       88
2223,         56,       78,       54
3345,         32,       12,       11
4321,         11,       10,       06
5234,         10,       10,       12
6123,         12,       06,       04

出力:

[6123, 12, 06, 04], [4321, 11, 10, 06] => 4.58257569495584
[5234, 10, 10, 12], [4321, 11, 10, 06] => 6.08276253029822
[6123, 12, 06, 04], [5234, 10, 10, 12] => 9.16515138991168
[4321, 11, 10, 06], [3345, 32, 12, 11] => 21.6794833886788
[6123, 12, 06, 04], [3345, 32, 12, 11] => 22.0227155455452
[5234, 10, 10, 12], [3345, 32, 12, 11] => 22.113344387496
[2223, 56, 78, 54], [1112, 23, 56, 88] => 52.2398315464359
[3345, 32, 12, 11], [2223, 56, 78, 54] => 82.3468275041607
[3345, 32, 12, 11], [1112, 23, 56, 88] => 89.1403387922662
[5234, 10, 10, 12], [1112, 23, 56, 88] => 89.7830719011106
[5234, 10, 10, 12], [2223, 56, 78, 54] => 92.217135067188
[4321, 11, 10, 06], [2223, 56, 78, 54] => 94.62029380635
[4321, 11, 10, 06], [1112, 23, 56, 88] => 94.7839648885823
[6123, 12, 06, 04], [2223, 56, 78, 54] => 98.0815986819138
[6123, 12, 06, 04], [1112, 23, 56, 88] => 98.3717439105356
于 2012-08-09T17:01:36.517 に答える