通过Perl中的数组遍历数据处理 [英] Data processing by iterating through an array in 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 with180
如果有两个以上的元素,然后每对 $ VEC2
值产生输出的一条线,每一个包含值 $ VEC 1
按 $ VEC 1
$ VEC2 $ C $之间的夹角> 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屋!