Re: conditional index of arrays
On Friday 04 Dec 2009 06:10:16 Eric Mooshagian wrote: Dear All, This is my first post. I present some subroutines that 1) create an index for one or more arrays and then 2) get summary statistics based on the index. I have 2 issues: First of all, based on a cursory look of your code, I should note that you may opt to use Statistics-Descriptive instead: http://search.cpan.org/dist/Statistics-Descriptive/ Caveat: I'm its maintainer on CPAN. 1. I would like to be able to create the index conditional on the values of another array, e.g., conceptually something like: my @index = defindex(\...@a,\...@b,\...@c) for \...@dv 150 dv 800 I don't understand this code. Do you want to use perldoc -f map: http://perldoc.perl.org/functions/map.html ? A few notes: 1. Don't do ampersand-subroutine: http://www.perlfoundation.org/perl5/index.cgi?subroutines_called_with_the_ampersand 2. You have three arrays passed as a reference. Please consider using named arguments, in case you have too many parameters: print_details( { first = John, last = Doe, city = Tel Aviv, . . . } ); However, I have no idea how to write the code to do this. Ideally I would be able to have several constraints (e.g., filter by reaction time, accuracy, etc). Any clues? Is there a specific keyword or topic I should search? I don't understand. You may look at some list operations from: 1. http://www.shlomifish.org/lecture/Perl/Newbies/lecture2/useful_funcs/ 2. http://search.cpan.org/perldoc?List::Util 3. http://search.cpan.org/dist/List-MoreUtils/ 2. This following section is redundant across the subroutines, but I cannot figure out how put it into another subroutine and return the result in a way that I can use it. I think I'm just not understanding how to correctly return/use the hash with multiple values per key. ( I want to maintain separate subroutines for each measure) my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } What you're doing here is looping over the keys, discarding the values and just incrementing the key. I would write this as (untested): sub get_combos_from_kv { my ($keys, $values) = @_; my %combos; foreach my $i (0 .. $#$keys) { my $key = $keys-[$i]; my $value = $values-[$i]; push @{$combos{$key}}, $value; } return \%combos; } (There may be a more lispy/haskelly way using the functions in List-Util and List-MoreUtils, but this code is also OK.) And you call it like this: my $combos = get_combos_from_kv(\...@keys, \...@values); Finally, I have no doubt people can suggest how make the code generally more perl like and efficient. Many thanks in advance for any help, Eric #!/usr/bin/perl use strict qw(vars subs); Why don't you have use strict 'refs' too? I.e: use strict; use warnings; It's good that you have strict and warnings. use List::Util qw(sum); #example data my @a = qw(Sub1 Sub1 Sub1 Sub1 Sub1 Sub1 Sub2 Sub2 Sub2 Sub2 Sub2); my @b = qw(left left left right right left right right left right right); my @c = qw(down up down down up up up down down up up); my @dv= (.87,.2,.655,.7,.5,.3,.1,.45,.70,.900,.3); I should note that these decimal floating-point fractions will not be exact, due to their constraints as base-2 fractions. See: http://docs.sun.com/source/806-3568/ncg_goldberg.html (Which I haven't read yet, but am aware of several of its implications.) my @acc= qw(c c c i c i c c c i c); ### my @index = defindex(\...@a,\...@b,\...@c); You should never use ampersand-subroutine-call: http://www.perlfoundation.org/perl5/index.cgi?subroutines_called_with_the_ampersand getmean(\...@index,\...@dv); getmedian(\...@index,\...@dv); getcount(\...@index,\...@dv); getmean(\...@index,\...@acc); #define the index sub defindex { my $i; my $k; my @combined; my @meshed; for ( $i=0; $i$#_+1; $i++) { $i $#_+1 can be written as $i @_ which is short for $i scalar(@_). This entire loop can be written as: for my $i (0 .. $#_) Other than that I should note that my personal preference is not to clobber the @_ with items and instead to pass them as an array reference. push(@combined,${array$i}=$_[$i]); Why are you using symbolic references and varvarname here: http://perl.plover.com/varvarname.html You should use an array. } @meshed = mesh(@combined); $j=0; while (@meshed){ my $merged = join('',splice(@meshed,0,$#_+1)); $#_+1 is better written
Re: conditional index of arrays
On Dec 3, 8:10 pm, ericmooshag...@gmail.com (Eric Mooshagian) wrote: I present some subroutines that 1) create an index for one or more arrays and then 2) get summary statistics based on the index. I have 2 issues: 1. I would like to be able to create the index conditional on the values of another array, e.g., conceptually something like: my @index = defindex(\...@a,\...@b,\...@c) for \...@dv 150 dv 800 I'm not sure since there are significant problems with the line above. Again I'm not sure but did you perhaps mean: my $size = @dv; my @index = definedx( \...@a,\...@b,\...@c ) if $size 150 and $size 800; Full strictures would expose some of the problems. Your code only imports 'vars' and 'subs'. In other words, you used: use strict qw/vars subs/; # better alternative: use strict; With 'use strict;', you'd see warnings like those below:: 'Possible precedence problem on bitwise operator at ...' (You probably intended the lower precedence 'and' ) 'Bareword dv not allowed while strict subs in use at ...' (You probably intended @dv here but the condition itself is the more serious problem. ) Also, the prefix '' is optional. See 'perldoc perlsub' for more info. Bottom line: it's a bad habit to include '' automatically. However, I have no idea how to write the code to do this. Ideally I would be able to have several constraints (e.g., filter by reaction time, accuracy, etc). Any clues? Is there a specific keyword or topic I should search? 2. This following section is redundant across the subroutines, but I cannot figure out how put it into another subroutine and return the result in a way that I can use it. I think I'm just not understanding how to correctly return/use the hash with multiple values per key. ( I want to maintain separate subroutines for each measure) my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } The above code can be replaced with: my %combos; @combos{ @{$_[0] } } = @{ $_[1] }; # a hash slice Looks like there are other pitfalls too such as your use of subroutine prototypes, etc. I'd recommend reviewing some of the tutorials too such as perlsub and perlref. -- Charles DeRykus -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org http://learn.perl.org/
Re: conditional index of arrays
On Dec 4, 2009, at 8:32 AM, Shlomi Fish wrote: On Friday 04 Dec 2009 06:10:16 Eric Mooshagian wrote: Dear All, This is my first post. I present some subroutines that 1) create an index for one or more arrays and then 2) get summary statistics based on the index. I have 2 issues: First of all, based on a cursory look of your code, I should note that you may opt to use Statistics-Descriptive instead: http://search.cpan.org/dist/Statistics-Descriptive/ Caveat: I'm its maintainer on CPAN. Thank you. I'll keep this mind, but I'm writing this, in part, to get a deeper understanding of some concepts. 1. I would like to be able to create the index conditional on the values of another array, e.g., conceptually something like: my @index = defindex(\...@a,\...@b,\...@c) for \...@dv 150 dv 800 I don't understand this code. Do you want to use perldoc -f map: http://perldoc.perl.org/functions/map.html ? If so, it's not obvious to me. To clarify, I want to be able to run the following: my $index = defindex(\...@a,\...@b); my @index = @$index; However, I want to be able to qualify which elements of the passed arrays should be included in the index. So, rows of data might look like this: @a @b @c @dv @accuracy Sub1leftdown.87 1 Sub1leftup .2 1 Sub1leftdown.6551 Sub1right down.7 0 Sub1right up .5 0 Sub1leftup .3 1 etc. I want to create an index for say, @a and @b, but conditional that only lines for which the value of @acc that are 1 are included. That is, the index subroutine should skip lines 4 and 5 in the above data. Even more importantly, I want users to be able to apply such arbitrary constraints at the subtoutine call rather than to write code for just this specific example. I'm very interested in learning how to do this sort of thing in general. A few notes: 1. Don't do ampersand-subroutine: http://www.perlfoundation.org/perl5/index.cgi?subroutines_called_with_the_ampersand 2. You have three arrays passed as a reference. Please consider using named arguments, in case you have too many parameters: print_details( { first = John, last = Doe, city = Tel Aviv, . . . } ); I will look into this, but I must admit that I thought named arguments are useful because you don't have to remember the order that argument should be passed. In this indexing function, the user should be able to order the arguments in any order they want. Is it still preferable to use named arguments? However, I have no idea how to write the code to do this. Ideally I would be able to have several constraints (e.g., filter by reaction time, accuracy, etc). Any clues? Is there a specific keyword or topic I should search? I don't understand. You may look at some list operations from: 1. http://www.shlomifish.org/lecture/Perl/Newbies/lecture2/useful_funcs/ 2. http://search.cpan.org/perldoc?List::Util 3. http://search.cpan.org/dist/List-MoreUtils/ 2. This following section is redundant across the subroutines, but I cannot figure out how put it into another subroutine and return the result in a way that I can use it. I think I'm just not understanding how to correctly return/use the hash with multiple values per key. ( I want to maintain separate subroutines for each measure) my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } What you're doing here is looping over the keys, discarding the values and just incrementing the key. I would write this as (untested): sub get_combos_from_kv { my ($keys, $values) = @_; my %combos; foreach my $i (0 .. $#$keys) { my $key = $keys-[$i]; my $value = $values-[$i]; push @{$combos{$key}}, $value; } return \%combos; } Thanks! I implemented this code. I was simply not dereferencing the returned hash correctly. (There may be a more lispy/haskelly way using the functions in List- Util and List-MoreUtils, but this code is also OK.) And you call it like this: my $combos = get_combos_from_kv(\...@keys, \...@values); Finally, I have no doubt people can suggest how make the code generally more perl like and efficient. Many thanks in advance for any help, Eric #!/usr/bin/perl use strict qw(vars subs); Why don't you have use strict 'refs' too? I.e: use strict; Honestly, it was simply because it was complaining about my use of refs. I fixed the problem per your suggestion about avoiding symbolic refs and varvarname.
conditional index of arrays
Dear All, This is my first post. I present some subroutines that 1) create an index for one or more arrays and then 2) get summary statistics based on the index. I have 2 issues: 1. I would like to be able to create the index conditional on the values of another array, e.g., conceptually something like: my @index = defindex(\...@a,\...@b,\...@c) for \...@dv 150 dv 800 However, I have no idea how to write the code to do this. Ideally I would be able to have several constraints (e.g., filter by reaction time, accuracy, etc). Any clues? Is there a specific keyword or topic I should search? 2. This following section is redundant across the subroutines, but I cannot figure out how put it into another subroutine and return the result in a way that I can use it. I think I'm just not understanding how to correctly return/use the hash with multiple values per key. ( I want to maintain separate subroutines for each measure) my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } Finally, I have no doubt people can suggest how make the code generally more perl like and efficient. Many thanks in advance for any help, Eric #!/usr/bin/perl use strict qw(vars subs); use warnings; use List::Util qw(sum); #example data my @a = qw(Sub1 Sub1 Sub1 Sub1 Sub1 Sub1 Sub2 Sub2 Sub2 Sub2 Sub2); my @b = qw(left left left right right left right right left right right); my @c = qw(down up down down up up up down down up up); my @dv= (.87,.2,.655,.7,.5,.3,.1,.45,.70,.900,.3); my @acc= qw(c c c i c i c c c i c); ### my @index = defindex(\...@a,\...@b,\...@c); getmean(\...@index,\...@dv); getmedian(\...@index,\...@dv); getcount(\...@index,\...@dv); getmean(\...@index,\...@acc); #define the index sub defindex { my $i; my $k; my @combined; my @meshed; for ( $i=0; $i$#_+1; $i++) { push(@combined,${array$i}=$_[$i]); } @meshed = mesh(@combined); $j=0; while (@meshed){ my $merged = join('',splice(@meshed,0,$#_+1)); $index[$j]=$merged; $i++; } return @index; } #end defindex # get the mean by index sub getmean (\...@\@) { my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } print ID\tMeans\n; my $key; my $mean; foreach $key (sort keys %combos) { my $mean = (sum(@{$combos{$key}}))/(scalar(@{$combos{$key}})); printf $key\t%.3f\n, $mean; } } #end of getmean #get median by index sub getmedian (\...@\@) { my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } print ID\tMedians\n; my $key; foreach $key (sort keys %combos) { my $count = scalar(@{$combos{$key}}); my @array = sort { $a = $b } @{$combos{$key}}; if ($count % 2) { my $median= $array[int($count/2)]; print $key\t$median\n; } else { my $median= ($array[$count/2] + $array[$count/2 - 1]) / 2; print $key\t$median\n; } } } # end of getmedian #get count by index sub getcount (\...@\@) { my @ke...@{$_[0]}; my @valu...@{$_[1]}; my %combos = (); my $i=0; foreach (@keys) { my $key=$keys[$i]; my $value=$values[$i]; push( @{$combos{$key}}, $value ); $i++; } print ID\tCounts\n; my $key; foreach $key (sort keys %combos) { my $count = scalar(@{$combos{$key}}); print $key\t$count\n; } } # end of getcount #borrowed from the List::MoreUtils Module by Tassilo von Parseval sub mesh (\...@\@;\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@\...@\@ \...@\@) { my $max = -1; $max $#$_($max = $#$_) for @_; map { my $ix = $_; map $_-[$ix], @_; } 0..$max; } -- To unsubscribe, e-mail: beginners-unsubscr...@perl.org For additional commands, e-mail: beginners-h...@perl.org