Home: Perl Programming Help: Beginner:
[SOLVED] Problem printing return value from a subroutine

zing
Novice

Oct 3, 2012, 7:31 PM

Views: 19071
 [SOLVED] Problem printing return value from a subroutine
Hi all,
I have this code
 Code
`#This program read the triplets from file named "data" into #an array of array. use strict; use warnings; use Data::Dumper; use Graph;  use Graph::Subgraph;  my @S;  while (<>) {         push @S, [ split ];     } print "-----TRIPLETS-------\n"; print Dumper \@S; #Make a copy of @S  my @trip = map { [@\$_] } @S;  # Find the number of vertices my @L; for my \$i ( 0 .. \$#S ) { for my \$j ( 0 .. \$#{ \$S[\$i] } ) { push (@L,\$S[\$i][\$j]);      }  } my %seen; @L = grep { ! \$seen{ \$_ }++ } @L; print " ----VERTICES------\n"; print Dumper \@L;   # Now lets generate the G(L) # In order to generate the G(L) we'll extract first two columns of S into another matrix my @GL=@S; splice(@\$_, 2, 1)    foreach @GL; print "----EDGE LIST TO BUILD G(L)-----\n"; print Dumper \@GL;  #my %h = map { \$_->[0] => \$_->[1] } @S; #print Dumper(\%h);   ##### CONNECTED COMPONENTS ########## my \$g = Graph->new( undirected => 1 );  my @a; my @b; for (my \$p = 0; \$p <= 2; \$p++) { \$a[\$p]=\$S[\$p][0];   }  for (my \$q = 0; \$q <= 2; \$q++) { \$b[\$q]=\$S[\$q][1];   }  for (my \$r = 0; \$r <= 2; \$r++) {  	\$g->add_edge(\$a[\$r], \$b[\$r]);  }  my @subgraphs = \$g->connected_components; my @allgraphs; my \$V = \$g->vertices; print "Number of taxa=\$V\n";   my \$q=scalar @subgraphs; print "Number of connected components ", \$q , "\n"; print "First connected component: ", @{ \$subgraphs[0] }, "\n"; print "First connected component element: ", \$subgraphs[0][1], "\n\n";   sub induced { my (@z)=@_; for my \$QT (\@z ){     #print Dumper \$QT;     for my \$triplet ( @trip ){         my %Pie;         undef @Pie{@\$QT};         delete @Pie{ @\$triplet };         print "@\$triplet\n" if keys(%Pie) <= ( @\$QT - @\$triplet ) ;         return (@\$triplet);     } }} my @C; my \$d; my \$p=\$#subgraphs+1; for (\$d=\$p; \$d >=1; \$d--)   {      print "component \$d = @{ \$subgraphs[\$d-1] }\n";     my \$qw=induced(@{ \$subgraphs[\$d-1] }); print "induced=\$qw\n";  }`
It takes in the data from data file ,the content of which is
 Code
`-----------DATA---------- b c a a c d d e b`
---OUTPUT----
 Code
`----TRIPLETS------- \$VAR1 = [           [             'b',             'c',             'a'           ],           [             'a',             'c',             'd'           ],           [             'd',             'e',             'b'           ]         ];  ----VERTICES------ \$VAR1 = [           'b',           'c',           'a',           'd',           'e'         ]; ----EDGE LIST TO BUILD G(L)----- \$VAR1 = [           [             'b',             'c'           ],           [             'a',             'c'           ],           [             'd',             'e'           ]         ]; Number of taxa=5 Number of connected components 2 First connected component: cba First connected component element: b  component 2 = e d induced=3 component 1 = c b a b c a induced=3`

Problem is with the last 5 lines of the output ,it should have been this
 Code
`component 2 = e d component 1 = c b a induced=b c a`
I know the problem is there in the way the subroutine return value is saved. Please suggest me why is this happening and how to fix it.

(This post was edited by zing on Oct 8, 2012, 10:14 AM)

Laurent_R
Veteran / Moderator

Oct 4, 2012, 1:25 AM

Views: 19054
 Re: [zing] Problem printing return value from a subroutine
Hi,

I haven't tried to understand your full program, but I think the problem you have is probably there:

 Code
`my \$qw=induced(@{ \$subgraphs[\$d-1] });`

The induced subroutine returns an array (@triplet), but \$qw is a scalar. If you are using an array in scalar context, you will get the number of elements of the array, rather than the elements of the array.

zing
Novice

Oct 4, 2012, 1:48 AM

Views: 19052
 Re: [Laurent_R] Problem printing return value from a subroutine
Hi Laurent,
I tried this as per your suggestion:
 Code
` my @qw=induced(@{ \$subgraphs[\$d-1] });     print Dumper @qw;`

The output
 Code
`component 2 = e d b c a Induced==\$VAR1 = 'b'; \$VAR2 = 'c'; \$VAR3 = 'a'; component 1 = c b a b c a b c a Induced==\$VAR1 = 'b'; \$VAR2 = 'c'; \$VAR3 = 'a';`

whereas I want this
 Code
`component 2 = e d component 1 = c b a induced=b c a`

Laurent_R
Veteran / Moderator

Oct 4, 2012, 8:39 AM

Views: 19026
 Re: [zing] Problem printing return value from a subroutine
Hi,

this is probably OK, because this is the way data dumper will print it the way you use it. But if you look closely at it, it says that the variable you are dumping contains 3 variables, b, c and a, whicj is what you expect.

You should try to pass Dumper a reference to \$qw.

zing
Novice

Oct 4, 2012, 8:49 AM

Views: 19024
 Re: [Laurent_R] Problem printing return value from a subroutine
Laurent maybe I couldnt explain properly.Let me explain what is wanted.Consider for example component 2. It has two vertices e,d. Now I want to see if any of the rows from "DATA" is a subset of these points.Now since each of the row of "DATA" has 3 vertices/points,therefore clearly for component 2 there isnt any induced line from DATA. Therefore there should be anything to print for the subroutine "induced" for this case.

But for component 1,which has vertices as = c,a,b; the first line of "DATA" which is "b c a" gets induced.

Similarly if component=a,b,c,d ; then first two rows of DATA get induced ,as they are both the subset of the component.
So what i want now is that,I want to save this induced vertices in a variable/array etc. AS i need to do further processing on this induced part.

(This post was edited by zing on Oct 4, 2012, 9:02 AM)

BillKSmith
Veteran

Oct 4, 2012, 9:15 AM

Views: 19015
 Re: [zing] Problem printing return value from a subroutine
The following changes should help
 Code
`for ( \$d = \$p; \$d >= 1; \$d-- ) {     print "component \$d = @{ \$subgraphs[\$d-1] }\n";     my @qw = induced( @{ \$subgraphs[ \$d - 1 ] } );     print Dumper \@qw; } print "induced=@qw\n";`

Extraneous output seems to be comming from the subroutine induced.
Good Luck,
Bill

zing
Novice

Oct 4, 2012, 11:02 AM

Views: 19013
 Re: [BillKSmith] Problem printing return value from a subroutine
Still no luck.
here's the output with the chages you suggested.
 Code
`component 2 = e d \$VAR1 = [           'b',           'c',           'a'         ]; component 1 = c b a b c a \$VAR1 = [           'b',           'c',           'a'         ]; induced=`
Also I didnt get the logic behind keeping
 Code
`print "induced=@qw\n";`
out of the loop. The induced content depends on the content of component,so it should be kept inside the loop.For if there are 5 components and 3 of them are capable of inducing then "keeping it outside for loop" logic wont work

BillKSmith
Veteran

Oct 4, 2012, 2:05 PM

Views: 19011
 Re: [zing] Problem printing return value from a subroutine
I did not claim a complete solution. I moved one print statement out of the loop because your expected output has only one copy of that output. Are you sure that your posted expected output is correct?

It is a good idea to use Data::Dumper as a debug tool. Perhaps you should remove the dumps as soon as you are convinced that they are correct. (They can be put back in to check out changes)
Good Luck,
Bill

Laurent_R
Veteran / Moderator

Oct 4, 2012, 3:38 PM

Views: 19009
 Re: [zing] Problem printing return value from a subroutine
Hi Zing,

I am traveling this week and don't have acces right now to a Perl environment, so I can't try your code. And it is too long for me to try to follow its logics manually.

But my impression is that you are expecting from Data::Dumper things that are beyond the scope of this module. Actually, I have the feeling that your program gives you what you need, but that you can't recognize it because you expect the same data in a format that is different from what Dumper provides you.

zing
Novice

Oct 4, 2012, 10:38 PM

Views: 18995
 Re: [BillKSmith] Problem printing return value from a subroutine
Bill , after commenting
 Code
`#print Dumper @qw;`
I got this
---------OUTPUT----------
 Code
`component 2 = e d component 1 = c a b b c a`

Clearly since, "b c a" is a subset of component1(c a b) therefore it gets printed. But Bill I just want to save this "b c a" in a suitable array/variable etc. As I need it for further processing.That's why I want to save this output,rather than just getting it printed.

Also there would be a case for example consider a component 3,which has these points= "a c d e". Then row 2nd and 3rd of "DATA" are a subset of these points.So for component3 I'm expecting this output
 Code
`component 3 = a c d e induced= a c d         d e b`
I want to save these induced values in a suitable data structure as I need to further process them.

(This post was edited by zing on Oct 4, 2012, 11:20 PM)

Laurent_R
Veteran / Moderator

Oct 5, 2012, 3:21 AM

Views: 18964
 Re: [zing] Problem printing return value from a subroutine
Clearly since, "b c a" is a subset of component1(c a b) therefore it gets printed. But Bill I just want to save this "b c a" in a suitable array/variable etc. As I need it for further processing.That's why I want to save this output,rather than just getting it printed.

But you have "b c a" stored in the @qw array (BTW, you should give it a more sensible name, but it is a different matter), what else do you need?

zing
Novice

Oct 5, 2012, 5:00 AM

Views: 18948
 Re: [Laurent_R] Problem printing return value from a subroutine
Laurent I get that,but if you see Post #7, u'll see that that @qw gets printed even when component 2 =" e d" (But it shouldn't get printed ).
Shouldnt it be something like this then ( if I keep this line "print Dumper @qw;" uncommented)
 Code
`component 2 = e d  component 1 = c b a  b c a  \$VAR1 = [            'b',            'c',            'a'          ];`
I hope Im clear.

(This post was edited by zing on Oct 5, 2012, 5:02 AM)

zing
Novice

Oct 5, 2012, 5:26 AM

Views: 18943
 Re: [zing] Problem printing return value from a subroutine
The code fails on this data
 Code
`---------DATA-------------- b c a a c d d e b e f g g d f h i g`

And the output is
 Code
`component 2 = e d g f component 1 = c a b b c a`
Which is wrong, because it should have been this
 Code
`component 2 = e d g f e f g g d f component 1 = c a b b c a`
Because with the vertices in component 2, we can have 4th & 5th row of DATA.

(This post was edited by zing on Oct 5, 2012, 5:28 AM)

zing
Novice

Oct 5, 2012, 1:29 PM

Views: 18921
 Re: [Laurent_R] Problem printing return value from a subroutine
Please let me know if you need any other input from me.
Help me solve this problem

BillKSmith
Veteran

Oct 5, 2012, 4:02 PM

Views: 18918
 Re: [zing] Problem printing return value from a subroutine
I am confused. Allow me to start over. I am unable to exactly duplicate your original problem with the following proceedure.
• Paste your code into editor.

• Restore newlines with perltidy

• Change input operator to <DATA>

• Add data to end of file[\li]
• Install Graph module on my system[\li]
• Remove reference to Graph::Subgraph -- not used

• I tried Laurent's suggestion from post 2. The resultls diverge even more from those in post 3.

Later posts bring up more issues. Let's settle the first one first. Please attach (this avoids the newline problem) a complete working copy of your script that we can both run. I have attached my script as a sample of what I need.
Good Luck,
Bill
Attachments: zing_2.pl (2.16 KB)

zing
Novice

Oct 6, 2012, 1:27 AM

Views: 18909
 Re: [BillKSmith] Problem printing return value from a subroutine
thanks for cleaning it up BillK. Let me reformulate the exact part concerned.
Guys the problem is like to check if an array is contained inside another array.
 Code
`perl -le '@x = qw(a b c d e f);             @y = qw(a d f);             \$n = grep { \$e = \$_; not grep { \$e =~ /\Q\$_/i } @x } @y;             print "Count of elements in (@y) that are NOT present in (@x) = \$n"            ' Count of elements in (a d f) that are NOT present in (a b c d e f) = 0`

So if the count is 0, you know that @y is a subset of @x and hence you want to return it from the "induced" subroutine.
I hope this would even clear out the mess. Now can this be incorporated as a subroutine.
The input will be DATA taken in as an array. The second array will hold the connected components.
 Code
`____DATA_____ b c a a c d d e b e f g g d f h i g`

@Components
 Code
`a b c a b d c e f d g`
So I want to see if any row of @DATA is contained inside @Components.
So the output expected is
 Code
`component 1 = a b c induced = b c a component = a b d c induced = b c a a c d component 3 = e f d g induced = e f g g d f`

(This post was edited by zing on Oct 6, 2012, 1:28 AM)

BillKSmith
Veteran

Oct 8, 2012, 6:32 AM

Views: 18849
 Re: [zing] Problem printing return value from a subroutine
I understand that you want subroutine induced to accept one component and return the first line of DATA which is a subset of it. Return an empty array if there is none. This subroutine is called for each component. I have not yet tried to integrate this with your graph code.

 Code
`use strict; use warnings; my @components = (     [qw(a b c)],     [qw(a b d c)],     [qw(e f d g)],     ); my @S; while (<DATA>) {     push @S, [split]; }  foreach my \$component (@components) {     print "component @\$component\n";     my @qw = induced ( \$component, \@S  );     print "Induced = @qw\n" if @qw; }  sub induced {     my (\$x, \$yy) = @_;     foreach my \$y (@\$yy) {         my %seen;         @seen{@\$x} = ();         my \$n = grep {!exists \$seen{\$_}} @\$y; #       print "Count of elements in (@\$y) that are NOT present in (@\$x) = \$n\n";         return @\$y if !\$n;     }     return (); } __DATA__ b c a a c d d e b e f g g d f h i g`
Good Luck,
Bill

zing
Novice

Oct 8, 2012, 10:14 AM

Views: 18817
 Re: [BillKSmith] Problem printing return value from a subroutine
Thanks everybody and BillK. Im marking this as solved.
BTW I have another problem(post 72049) which uses the code from this thread.
Please see to it if you can help me on that.