Arrays 在perl中通过迭代数组进行数据处理

Arrays 在perl中通过迭代数组进行数据处理,arrays,perl,Arrays,Perl,我有这个剧本: use strict; use warnings; use diagnostics; use Math::Vector::Real; use constant DEG_PER_RAD => 45 / atan2(1, 1); my ( $source, $out ) = qw/ OUT4 OUTABA12 /; open my $in_fh, '<', $source or die qq{Unable to open "$source" for input: $

我有这个剧本:

use strict;
use warnings;
use diagnostics;
use Math::Vector::Real;
use constant DEG_PER_RAD => 45 / atan2(1, 1);

my ( $source, $out ) = qw/ OUT4 OUTABA12 /;

open my $in_fh,  '<', $source or die qq{Unable to open "$source" for input: $!\n};
open my $out_fh, '>', $out    or die qq{Unable to open "$out" for output: $!\n};

my @data;
push @data, V(split) while <$in_fh>;

my @aoa;
for my $i ( 0 .. $#data ) {
    for my $j ( 0 .. $#data ) {
        my $val1 = $data[$i];
        my $val2 = $data[$j];

        if ($val1 != $val2) {
            my $math = sqrt(($val1->[0] - $val2->[0])**2 +
                ($val1->[1] - $val2->[1])**2 +
                ($val1->[2] - $val2->[2])**2);
            if ($math < 2.2) {
                    push @aoa, [@$val1, @$val2, $math];
            }
        }
    }
}

for my $k ( 0 .. $#aoa-1 ) {
    my $aoadata1 = $aoa[$k];
    my $aoadata2 = $aoa[$k+1];
    my $vect1 = [ @{ $aoa[$k] }[0..2] ];
    my $vect2 = [ @{ $aoa[$k+1] }[0..2] ];
    my $vect3 = [ @{ $aoa[$k] }[3..5] ];
    my $vect4 = [ @{ $aoa[$k+1] }[3..5] ];
    my $math1 = [ @{ $aoa[$k] }[6] ];
    my $math2 = [ @{ $aoa[$k+1] }[6] ];
    my @matha = @$math1;
    my @mathb = @$math2;
    my @vecta = @$vect1;
    my @vectb = @$vect2;
    my @vectc = @$vect3;
    my @vectd = @$vect4;
            if ( @vecta != @vectb ) {
                print "180\n";
            }
}
然后生成这个中间数组:

18.474525 20.161419 20.33903 18.333228 21.649157 21.125111 1.68856523042908
18.474525 20.161419 20.33903 20.371077 19.675844 19.77649 2.03694472701863
18.474525 20.161419 20.33903 17.04323 19.3106 20.148842 1.67590865596249
21.999333 20.220667 19.786734 20.371077 19.675844 19.77649 1.71701911532778
21.999333 20.220667 19.786734 22.941106 19.105412 19.069893 1.62621988606553
18.333228 21.649157 21.125111 18.474525 20.161419 20.33903 1.68856523042908
20.371077 19.675844 19.77649 18.474525 20.161419 20.33903 2.03694472701863
20.371077 19.675844 19.77649 21.999333 20.220667 19.786734 1.71701911532778
17.04323 19.3106 20.148842 18.474525 20.161419 20.33903 1.67590865596249
22.941106 19.105412 19.069893 21.999333 20.220667 19.786734 1.62621988606553
这是一对坐标,后面是列表中的另一对坐标,后面是它们之间的距离

我一直试图做的是进入程序的下半部分工作——但我不知道如何像我需要的那样通过阵列工作

如果中间数组中有一行的第一组坐标与所有其他行都是唯一的,则只需打印该行中的第一组坐标,然后打印180。例如,正在运行的数组中的最后一行

print "@vecta 180\n";
应返回,对于该行:

22.941106 19.105412 19.069893 180
否则,对于中间数组的每一行,我想看看一条直线的前3个坐标是否与第二条直线的前3个坐标匹配,如果匹配,我需要从这两条直线上取第二组坐标,减去这两条直线上第一组相同的坐标,然后求减法后两个次坐标之间的角度。类似于此:

my $varvec1 = V( @$vect3 );
my $varvec2 = V( @$vect4 );
my $varnorm = V( @$vect1 );
my $nvect1 = $varvec1 - $varnorm ;
my $nvect2 = $varvec2 - $varnorm ;
my $degrees = atan2($nvect1, $nvect2) * DEG_PER_RAD;
print "$varnorm $degrees\n";
在中间层的前3行上运行应该返回:

18.474525 20.161419 20.33903 *Some Value* 
18.474525 20.161419 20.33903 *Some Value* 
18.474525 20.161419 20.33903 *Some Value* 
在第一条线和第二条线,第一条线和第三条线,然后第二条线和第三条线之间,通过上述角度计算得出一些值

总体而言,该计划将理想地为我提供:

 18.474525 20.161419 20.33903 *Some Value*
 18.474525 20.161419 20.33903 *Some Value*
 18.474525 20.161419 20.33903 *Some Value*
 21.999333 20.220667 19.786734 *Some Value*
 21.999333 20.220667 19.786734 *Some Value*
 18.333228 21.649157 21.125111 180
 20.371077 19.675844 19.77649 *Some Value*
 20.371077 19.675844 19.77649 *Some Value*
 17.04323 19.3106 20.148842 180
 22.941106 19.105412 19.069893 180
我的主要问题是正确地运行数据,我可以设置计算和变量分配。有人能帮我解决这个问题吗?提前谢谢

编辑-对Sobrique的响应

当我实施第二部分(我假设也实施了第一部分)时,您的其他建议也是如此:

my %seen;

for my $index ( 0 .. $#aoa ) {
    my $coord_key = join( ":", @{ $aoa[$index] }[ 0 .. 2 ] );
    if ( $seen{$coord_key} <= 1 ) {
        print V( @{$aoa[$index]}[0..2] ) . " 180\n";
    }
    else {
        last unless $aoa[ $index + 1 ]; #in case out of bounds
        my $varvec1 = V( @{ $aoa[$index] }[ 3 .. 5 ] );
        my $varvec2 = V( @{ $aoa[ $index + 1 ] }[ 3 .. 5 ] );
        my $varnorm = V( @{ $aoa[$index] }[ 0 .. 2 ] );
        my $nvect1  = $varvec1 - $varnorm;
        my $nvect2  = $varvec2 - $varnorm;
        my $degrees = atan2( $nvect1, $nvect2 ) * DEG_PER_RAD;
        print "$varnorm $degrees\n";

    }
my%seed;
对于我的$index(0..$#aoa){
我的$coord_key=join(“:”,@{$aoa[$index]}[0..2]);
如果($seen{$coord_key}那么对于第一部分:

如果中间数组中有一行的第一组坐标与所有其他行都是唯一的,则只需打印该行中的第一组坐标和180。例如数组中的最后一行

我有点懒,并且假设
加入
就足够了。它应该是纯数值的东西。否则,您可以实现更具体的数组等价性测试

use Data::Dumper;
print Dumper \@aoa;

my %seen;

foreach my $row (@aoa) {
    my $coord_key = join (":", @$row[0..2] );
    print $coord_key,"\n";
    $seen{$coord_key}++; 
}

foreach my $row ( @aoa ) { 
   my $coord_key = join (":", @$row[0..2] );
   print "Unique:  @$row[0..2] 180\n" unless $seen{$coord_key} > 1;
}

这将吐出:

Unique:  18.333228 21.649157 21.125111 180
Unique:  17.04323 19.3106 20.148842 180
Unique:  22.941106 19.105412 19.069893 180
我认为这是理想的结果

第二部分——我又迷路了,但我认为你应该可以做类似的事情

也许是这样的

for my $index ( 0 .. $#aoa ) {
    my $coord_key = join( ":", @{ $aoa[$index] }[ 0 .. 2 ] );
    if ( $seen{$coord_key} <= 1 ) {
        print "Unique:  @{$aoa[$index]}[0..2] 180\n";
    }
    else {
        last unless $aoa[ $index + 1 ]; #in case out of bounds
        my $varvec1 = V( @{ $aoa[$index] }[ 3 .. 5 ] );
        my $varvec2 = V( @{ $aoa[ $index + 1 ] }[ 3 .. 5 ] );
        my $varnorm = V( @{ $aoa[$index] }[ 0 .. 2 ] );
        my $nvect1  = $varvec1 - $varnorm;
        my $nvect2  = $varvec2 - $varnorm;
        my $degrees = atan2( $nvect1, $nvect2 ) * DEG_PER_RAD;
        print "$varnorm $degrees\n";

    }
}
看起来您正在打印
$varnorm
,其中隐式包含
{}
。您可以修改:

print "Unique:  @{$aoa[$index]}[0..2] 180\n";
致:

或:

或者用
join(“\t”),
将它们粘在一起制成表格或其他东西

编辑:对于数组比较-我建议的方法非常基本,并且会被一些事情绊倒

您可以改为执行以下操作:

foreach my $row (@aoa) {
    $seen{$row->[0]}{$row->[1]}{$row->[2]}++;
}
以及:


if($seed{$aoa[$index][0]}{$aoa[$index][1]}{$aoa[$index][2]}这是一篇重复的帖子,我错误地将它添加到了你原来的问题中,而不是这个新问题中。我认为这是正确的

我已经使用了我在评论中描述的模块的功能

  • 我将向量作为对象,避免直接访问其内容

  • 我将
    $vec1
    $vec2
    之间的距离计算为
    abs($vec2-$vec1)

  • 我使用类的stringify功能来显示它,而不是提取代码中的单个值

我还更改了中间数据格式。不再保留距离,因为这是不必要的,数组
@groups
现在包含一个数组,用于具有公共第一个向量的每组向量对。每组的形式如下

[ $vec1, $vec2, $vec2, $vec2, ... ]
我使用中的
first
函数查找每个新向量对所属的组。如果找到具有匹配的第一个值的现有组,则第二个向量将被推到组的末尾;否则将创建一个新组,看起来像
[$vec1,$vec2]

构建
@groups
数组后,将再次对其进行处理以生成输出

  • 如果组中只有两个值,则它们是唯一点的
    $vec1
    $vec2
    $vec1
    180

  • 如果有两个以上的元素,则为每对
    $vec2
    值生成一行输出,每对值均包含
    $vec1
    值以及由
    $vec1
    形成的两个增量与该对中的每一
    $vec2
    之间的角度



你的代码缩进怎么了?问题的格式很好,但是你的代码中有一些奇怪的空格?懒惰?:)@simbabque很大一部分是为了跟踪变量赋值的类型。但是,是的,部分是懒惰。很好的回答;)
perltidy
对这一点很好。我要问一下-为什么你要将一个匿名数组赋给一个标量,然后再将它转换回一个数组。例如,
my$vect1=[@{$aoa[$k]}[0..2]];my@vecta=@$vect1;
?我必须说-我想这就是你的问题所在。你的代码增加了额外的复杂度,但没有任何好处-现在很难解开它。我很难理解你的代码试图做什么,甚至在理解你试图完成什么之前,这使得de安装窃听器要困难得多。谢谢!你肯定正确地解释了我的问题,我试图尽可能地清楚,但我为留下的模糊性感到抱歉。然而,我确实用我实现的你的答案的解释更新了我的问题,以及我的实现导致的错误。我非常感激
print "Unique:  @{$aoa[$index]}[0..2] 180\n";
print V( @{$aoa[$index]}[0..2] ) . " 180\n";
print "$varnorm $degrees\n";
print "@{ $aoa[$index] }[ 0 .. 2 ] $degrees\n";
foreach my $row (@aoa) {
    $seen{$row->[0]}{$row->[1]}{$row->[2]}++;
}
if ( $seen{$aoa[$index][0]}{$aoa[$index][1]}{$aoa[$index][2]} <= 1 ) { 
       #....
}
[ $vec1, $vec2, $vec2, $vec2, ... ]
use strict;
use warnings;

use Math::Vector::Real qw/ V /;
use List::Util qw / first /;

use constant DEG_PER_RAD => 45 / atan2(1, 1);

my ( $source, $out ) = qw/ OUT4  OUTABA12 /;

open my $in_fh,  '<', $source or die qq{Unable to open "$source" for input: $!\n};

my @data = map V(split), <$in_fh>;

my @groups;

for my $vec1 ( @data ) {
    for my $vec2 ( @data ) {

        next if abs($vec2 - $vec1) > 2.2 or $vec2 == $vec1;

        my $group = first { $_->[0] == $vec1 } @groups;

        if ( $group ) {
            push @$group, $vec2;
        }
        else {
            push @groups, [ $vec1, $vec2 ];
        }
    }
}

open my $out_fh, '>', $out or die qq{Unable to open "$out" for output: $!\n};
select $out_fh;

for my $group ( @groups ) {

    my ($vec1, @vec2) = @$group;

    if ( @vec2 == 1 ) {
        print "$vec1 180\n";
        next;
    }

    for my $i ( 0 .. $#vec2-1 ) {
        for my $j ( $i+1 .. $#vec2 ) {
            my ($vec2a, $vec2b) = @vec2[$i, $j];
            my $angle = atan2( $vec2a - $vec1, $vec2b - $vec1 ) * DEG_PER_RAD;
            print "$vec1 $angle\n";
        }
    }

}
{18.474525, 20.161419, 20.33903} 114.61436195896
{18.474525, 20.161419, 20.33903} 115.382649331314
{18.474525, 20.161419, 20.33903} 130.002084392181
{21.999333, 20.220667, 19.786734} 109.204553032216
{18.333228, 21.649157, 21.125111} 180
{20.371077, 19.675844, 19.77649} 143.673572115941
{17.04323, 19.3106, 20.148842} 180
{22.941106, 19.105412, 19.069893} 180