通过Perl中的数组遍历数据处理 [英] Data processing by iterating through an array in perl

查看:287
本文介绍了通过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: $!\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";
            }
}

,与此输入文件,坐标列表启动:

Which starts with this input file, a list of coordinates :

18.474525 20.161419 20.33903
21.999333 20.220667 19.786734
18.333228 21.649157 21.125111
20.371077 19.675844 19.77649
17.04323 19.3106 20.148842
22.941106 19.105412 19.069893

然后产生这个中间数组:

which then produces this intermediate array :

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

其是对坐标,接着由另一对从该列表中的坐标,然后通过它们之间的距离。

which is a pair of coordinates, followed by another pair of coordinates from that list, followed by the distance between them.

我一直试图做的是让该方案下半年的工作 - 但我一直对如何通过阵列工作像我需要不知道。

What I've been trying to do is to get to the second half of the program to work - but I've no idea on how to work through the array like i need to.

如果有谁的第一组坐标的中间阵列中的行是从所有其他行唯一的,它应该简单地打印第一坐标设置该行中和180如在基于阵列的最后一行运行

If there is a row in the intermediate array who's first set of coordinates is unique from all other rows, it should simply print the first coordinate set in that row and 180. Such as the last row in the array- running

print "@vecta 180\n";

应该返回,该行:

Should return, for that line:

22.941106 19.105412 19.069893 180

否则,用于中间阵列的每一行,我想,看是否有行的第3坐标匹配的第二行的前三个坐标,并且如果他们这样做我需要采取所述第二组坐标从两行,减去第一组相同的每个从他们的两行的坐标,然后找到减法后的两个辅助坐标之间的角度。一个类似于此:

Otherwise, for each row of the intermediate array, I would like to see if the first 3 coordinates of a line match the first three coordinates of the second line, and if they do I need to take the second set of coordinates from the two lines, subtract the first identical set of coordinates on each of the two lines from them, and then find the angle between the two secondary coordinates after the subtraction. Something akin to this:

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";

运行上的前三行中的中间的应返回:

Running that on the first 3 rows of the intermediate should return:

18.474525 20.161419 20.33903 *Some Value* 
18.474525 20.161419 20.33903 *Some Value* 
18.474525 20.161419 20.33903 *Some Value* 

使用的<青霉>一些值的从上述角度计算的第一行和第二行,所述第一线和第三线,然后在第二线路和第三线路之间发生所衍生的。

With the Some Value's being derived from the above angle calculation happening between the first line and the second line, the first line and the third line, and then the second line and the third line.

作为一个整体,该计划将最好给我:

As a whole, the program would ideally give me:

 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

我的主要问题是通过数据运行正常,我可以设置计算和变量赋值。谁能帮我这个?提前致谢。

My main issue is running through the data correctly, I can set up the calculations and variable assignments. Can anyone help me out with this? Thanks in advance.

编辑 - 响应Sobrique

Edit - Response to Sobrique

当我与你有如此的其他建议落实第二部分(我假设实现了第一部分为好):

When I implement the second part (Which I assume implements the first part as well) with the other suggestions you had as so:

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";

    }

我得到:

Use of uninitialized value within %seen in numeric le (<=) at
    /Users/a7c/exe/distscript.pl line 64, <$in_fh> line 6 (#1)
    (W uninitialized) An undefined value was used as if it were already
    defined.  It was interpreted as a "" or a 0, but maybe it was a mistake.
    To suppress this warning assign a defined value to your variables.

    To help you figure out what was undefined, perl will try to tell you
    the name of the variable (if any) that was undefined.  In some cases
    it cannot do this, so it also tells you what operation you used the
    undefined value in.  Note, however, that perl optimizes your program
    anid the operation displayed in the warning may not necessarily appear
    literally in your program.  For example, "that $foo" is usually
    optimized into "that " . $foo, and the warning will refer to the
    concatenation (.) operator, even though there is no . in
    your program.

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

您绝对间$ P $正确PTED。我不太确定如何虽然除去非数字LE问题,底部结果似乎搞砸了的缘故吧。

Which you definitely interpreted correctly. I'm not quite sure how to remove the non-numeric LE issue though, and the bottom results seems to be messed up because of it.

推荐答案

这是我错误地添加到你原来的问题,而不是为这个新副本职位。我认为这是正确的。

This is a duplicate post that I mistakenly added to your original question instead of to this new one. I think it's correct

我用 数学:: Vector的设施::房地产 正如我在评论中描述模块

I've used the facilities of the Math::Vector::Real module as I described in a comment


  • 我离开向量作为对象,并避免直接访问他们的内容

  • I leave the vectors as objects and avoid accessing their their contents directly

我计算 $ VEC 1 $ VEC2 ABS之间的距离($ VEC2 - $ VEC 1)

我用的是类的的字符串化的显示,而不是在我的code提取单个值它的能力

I use the class's stringify ability to display it instead of extracting the individual values in my code

我也改变了中间数据格式。距离不再保留,因为它是没有必要的,而数组 @groups 现在包含每个组都有一个共同的第一矢量矢量对的数组。每个组的形式的

I have also changed the intermediate data format. The distance is no longer kept because it's not necessary, and the array @groups now contains an array for each group of vector pairs that have a common first vector. Each group is of the form

[ $vec1, $vec2, $vec2, $vec2, ... ]

和我使用第一通过 <功能code>列表::的Util 地发现,每一个新的载体在对所属的组。如果找到了匹配的第一个值,那么第二个向量是刚刚推出的现有组到组的端部;否则一个新的组创建,看起来像 [$ VEC 1,$ VEC2]

一旦 @groups 阵列构建,它再次处理以产生输出

Once the @groups array is built, it is processed again to generate the output


  • 如果有该组中只有两个值那么他们是 $ VEC 1 $ VEC2 的一个独特之处。 $ VEC 1 印有 180

  • If there are only two values in the group then they are $vec1 and $vec2 of a unique point. $vec1 is printed with 180

如果有两个以上的元素,然后每对 $ VEC2 值产生输出的一条线,每一个包含值 $ VEC 1 按 $ VEC 1 $ VEC2 C>在对

If there are more than two elements then a line of output is generated for every pair of $vec2 values, each containing the value $vec1 together with the angle between the two delta formed by $vec1 and each $vec2 in the pair


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

这篇关于通过Perl中的数组遍历数据处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆