0

I am considering this answer which uses a single array reference of points, where a point is a reference to a two-element array. My original code of the question (function extract-crossing) uses two separate arrays $x and $y here which I call like this:

my @x = @{ $_[0] }; my @y = @{ $_[1] };
...
return extract_crossing(\@x, \@y);

The new code below based on the answer takes (x, y) and returns a single datatype, here x intercept points:

use strict; use warnings;    
use Math::Geometry::Planar qw(SegmentLineIntersection);
use Test::Exception;

sub x_intercepts {
   my ($points) = @_;

   die 'Must pass at least 2 points' unless @$points >= 2;

   my @intercepts;
   my @x_axis = ( [0, 0], [1, 0] );

   foreach my $i (0 .. $#$points - 1) {
     my $intersect = SegmentLineIntersection([@$points[$i,$i+1],@x_axis]);
     push @intercepts, $intersect if $intersect;
   }

   return \@intercepts;
}

which I try to call like this:

my @x = @{ $_[0] }; my @y = @{ $_[1] };  
...
my $masi = x_intercepts(\@x);
return $masi; 

However, the code does not make sense. I am confused about passing the "double array" to the x_intercepts() function.

How can you make the example code clearer to the original setting?

4
  • 1
    Ah, I see what you're saying. As I said in my answer to your other question, "Note that this implementation accepts a single array reference of points, where a point is a reference to a two-element array, instead of separate array references of x- and y-coordinates." You're trying to pass a reference to a single-element array to x_intercepts; it expects a reference to an array of points, e.g. my $points = [ [0, 0], [1, 2], [-1, -1] ]; x_intercepts($points); Commented May 11, 2015 at 15:08
  • 1
    Pass an array reference of points. If you want to find the x-intercept of the line segment from (-1, -1) to (1, 1), you would call my $intercept = x_intercepts( [ [-1, -1], [1, 1] ] ); The result will also be an array reference of points, in this case [ [0, 0] ], representing a single intercept at the origin. Commented May 11, 2015 at 15:35
  • 2
    That's exactly what it does. If you pass [ [-1, -1], [1, 1], [3, -1] ] to represent the two contiguous line segments from (-1, -1) to (1, 1) and (1, 1) to (3, -1), you'll get two intercepts: [ [0, 0], [2, 0] ] Commented May 11, 2015 at 15:50
  • 2
    If you want to pass an arrayref of x-coordinates and an arrayref of y-coordinates, you'll have to change the code accordingly. As for the "data type" that is being passed to the function, please re-read my comments above; I've given several examples already. Commented May 11, 2015 at 16:09

1 Answer 1

1

If I am understanding the problem here, @ThisSuitIsBlackNot++ has written a function (x_intercepts which is available in the thread: Function to extract intersections of crossing lines on axes) that expects its argument to be a reference to a list of array references. The x_intercepts subroutine in turn uses a function from Math::Geometry::Planar which expects the points of a line segment to be passed as series of array references/anonymous arrays that contain the x,y values for each point.

Again - it is not entirely clear - but it seems your data is in two different arrays: one containing all the x values and one with the corresponding y values. Is this the case? If this is not correct please leave a comment and I will remove this answer.

If that is the source of your problem then you can "munge" or transform your data before you pass it to x_intercepts or - as @ThisSuitIsBlackNot suggests - you can rewrite the function. Here is an example of munging your existing data into an "@input_list" to pass to x_intercepts.

my @xs = qw/-1 1 3/;
my @ys = qw/-1 1 -1 /;

my @input_list ;
foreach my $i ( 0..$#ys ) {
   push @input_list,  [ $xs[$i], $ys[$i] ]  ;
}

my $intercept_list = x_intercepts(\@input_list)  ;
say join ",", @$_ for @$intercept_list ;

Adding the lines above to your script produces:

Output:

0,0
2,0

You have to be very careful doing this kind of thing and using tests to make sure you are passing the correctly transformed data in an expected way is a good idea.


I think a more general difficulty is that until you are familiar with perl it is sometimes tricky to easily see what sorts of values a subroutine is expecting, where they end up after they are passed in, and how to access them.

A solid grasp of perl data structures can help with that - for example I think what you are calling a "double array" or "double element" here is an "array of arrays". There are ways to make it easier to see where default arguments passed to a subroutine (in @_) are going (notice how @ThisSuitIsBlackNot has passed them to a nicely named array reference: "($points)"). Copious re-reading of perldocperbsub can help things seem more obvious.

References are key to understanding perl subroutines since to pass an array or hash to a subrouting you need to do so by references. If the argument passed x_intercepts is a list of two lists of anonymous arrays then when it is assigned to ($points), @$points->[0] @$points->[1] will be the arrays contain those lists.

I hope this helps and is not too basic (or incorrect). If @ThisSuitIsBlackNot finds the time to provide an answer you should accept it: some very useful examples have been provided.

Sign up to request clarification or add additional context in comments.

4 Comments

foreach my $i ( 0..$#y ) { push @input_list, [ $x[$i], $y[$i] ] ; steps through both arrays element by element until the end of the @y array (since each is a list of linked x,y points both arrays must by definition be the same length) and then pushes the elements - as a pair - onto @input_list inside an anonymous array (viz. the [] constructor surrounding them). There may be another way to do this but this is simple and readable.
Thanks for accepting my answer but it is difficult to tell to what part of the question it responds exactly. You may have noticed your question is starting to get down votes since it is very long and introduces new questions (along with error output not strictly related to the original question), and other material that should be in comments. The question also has too many comments which we should remove - at least once the body of the original post is improved.
I removed the comments and managed to reduce the case only here stackoverflow.com/q/30247937/54964 Something basic, I am doing wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.