Re: conditional index of arrays

2009-12-04 Thread Shlomi Fish
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

2009-12-04 Thread C.DeRykus
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

2009-12-04 Thread Eric Mooshagian


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

2009-12-03 Thread Eric Mooshagian

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