sdslrn123 has asked for the wisdom of the Perl Monks concerning the following question:
#!/usr/bin/perl
@foo= ("apple","orange","pear","pear","mango","apple");
for (@foo) {
$bar{$_}++;
}
while ( ($k,$v) = each %bar ) {
if ($v =~ 1){
print "$k appears $v time\n";
}
elsif ($v !=~ 1){
print "$k appears $v times\n";
}
}
The above code works nicely with a one column set of data:
apple
orange
pear
pear
mango
apple
For me the next stage is working with a 2-column set of data:
apple Tom
orange Tom
pear Tom
mango David
apple David
How would I go about creating a program that outputs:
APPLE appears 2TIMES associated with TOM and DAVID
ORANGE appears 1TIME associated with TOM
...e.t.c
I am hoping to extend this to data that has lots of rows of this type of 2 column data. My thinking is playing around with hashes?
Re: Counting Data in two columns?
by ikegami (Patriarch) on Jun 15, 2006 at 00:13 UTC
|
For me the next stage is working with a 2-column set of data:
Check out printf and sprintf
How would I go about creating a program that outputs:
You could create a hash with fruit for key and a list of persons for value.
| [reply] [d/l] [select] |
|
Thank You, everyone for your help! I am just confused with the following example. I think it is an inverted form of the original example I performed:
%HoA = (
flintstones => [ "fred", "barney" ],
jetsons => [ "fred", "jane", "elroy" ],
simpsons => [ "fred", "marge", "bart" ],
);
If the family names (jetsons, simpsons) are always different but elements within each of the familes may or may not match.
If I want to show that:
"fred" is a name that can be found in 3 families = [flintstones, jetso
+ns, simpsons]
e.t.c
Is this possible with this hash formation? | [reply] [d/l] [select] |
|
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %hoa = (
flintstones => [ "fred", "barney" ],
jetsons => [ "fred", "jane", "elroy" ],
simpsons => [ "homer", "marge", "bart" ],
);
my @freds = grep { $hoa{$_}->[0] eq 'fred' } sort keys %hoa;
print Dumper \@freds;
| [reply] [d/l] |
|
|
|
Basically my data is subject to change but will follow a format as follows where I will have a unique "Family Name" followed by "--" followed by various "family members". The contents of the data are unknown to me apart from the format:
Data is a text file as follows:
FLINTSTONES -- BARNEY, FRED, WILMA
JETSONS -- MAX, TONY, WILMA
SIMPSONS -- LISA, BARNEY, WILMA, HOMER
ALCATRAZ -- ELIJAH, MAX, WILMA
I know I can grab this into an array called @Dopli.
And split each line $unix at "--" into an array @trainer
Is there a way of pushing each array into a hash using
$trainer[0] and $trainer1.
sub nice_list {
return '' if @_ == 0;
return shift if @_ == 1;
my $last = pop;
return join(', ', @_) . " and $last";
}
my $unix;
my @dopli;
my @trainer;
foreach $unix (@dopli){
@trainer = split ('=', $unix);
my %is_eaten_by = (
$trainer[0] => [ qw($trainer[1]) ],
);
foreach my $fruit (keys %is_eaten_by) {
my $eaters = $is_eaten_by{$fruit};
my $num_eaters = @$eaters;
my $s = $num_eaters == 1 ? 's' : '';
my $p = $num_eaters == 1 ? '' : 's';
print("$num_eaters person$p eat$s ${fruit}s: ",
nice_list(@$eaters), "\n");
}
}
Ultimately I am looking to print:
BARNEY can be found 2: FLINTSTONES SIMPSONS
FRED can be found 1: FLINTSTONES
WILMA can be found 4: FLINTSTONES JETSONS SIMPSONS ALCATRAZ
MAX can be found 2: JETSONS ALCATRAZ
and so forth...
Thanks for any kind of help or advice | [reply] [d/l] [select] |
|
FLINTSTONES -- BARNEY, FRED, WILMA
JETSONS -- MAX, TONY, WILMA
SIMPSONS -- LISA, BARNEY, WILMA, HOMER
ALCATRAZ -- ELIJAH, MAX, WILMA
to
my %is_in_show = (
MAX => [ 'JETSONS', 'ALCATRAZ' ],
WILMA => [ 'FLINTSTONES', 'JETSONS', 'SIMPSONS', 'ALCATRAZ' ],
HOMER => [ 'SIMPSONS' ],
ELIJAH => [ 'ALCATRAZ' ],
...
);
when you read the file. The following accomplishes this:
while (<FILE>) {
chomp;
my ($show, $names) = split(/ -- /);
my @names = split(/, /, $names);
foreach my $name (@names) {
push(@{$is_in_show{$name}}, $show);
}
}
| [reply] [d/l] [select] |
Re: Counting Data in two columns?
by graff (Chancellor) on Jun 15, 2006 at 03:14 UTC
|
I had never seen the "=~" operator used for numeric comparison before. This is called the "binding" operator, described in perlop as follows: "binds a scalar expression to a pattern match."
So, when you do this: if ( $v =~ 1 ) what's really happening is that the numeric "1" is being converted to a string and used as a regular expression, and the condition will be true if the current value of $v, when converted to a string, contains a digit "1". Try the following command line (may need to fiddle with the quotes, if you're using an ms-dos shell):
perl -e '$x = 213; print "got a one\n" if ($x =~ 1)'
For me, that prints "got a one". For comparing numeric values, you want:
if ( $v == 1 )
and of course, if that condition proves to be false, do you really need to test again for this condition?
elsif ( $v != 1 )
| [reply] [d/l] [select] |
Re: Counting Data in two columns?
by neniro (Priest) on Jun 15, 2006 at 08:06 UTC
|
You can use a HoH for this:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %fruits;
while (<DATA>) {
chomp;
my @row = split /\s+/, $_, 2;
warn @row and next unless @row == 2;
$fruits{$row[0]}->{$row[1]}++;
}
for my $fruit (sort keys %fruits) {
my $sum = 0;
$sum += $fruits{$fruit}->{$_} for keys %{$fruits{$fruit}};
$sum = $sum == 1 ? $sum . ' TIME ' : $sum . ' TIMES ';
my $people = '';
my @people = keys %{$fruits{$fruit}};
for (0..$#people) {
$people .= $_ != $#people ?
uc ($people[$_]) . ' and ' :
uc ($people[$_]);
}
print uc $fruit, ' appears ', $sum, 'associated with ', $people, "
+\n";
}
__DATA__
apple Tom
orange Tom
pear Tom
mango David
apple David
| [reply] [d/l] |
Re: Counting Data in two columns?
by neniro (Priest) on Jun 15, 2006 at 10:32 UTC
|
#!/usr/bin/perl
use strict;
use warnings;
package Fruit;
use Moose;
has 'count' => ( is => 'rw' );
has 'person' => ( isa => 'ArrayRef', is => 'rw' );
sub add_person {
my $self = shift;
my $person = shift;
unless (grep {$_ eq $person} @{$self->{person}}) {
push @{$self->{person}}, $person;
}
}
sub inc {
my $self = shift;
$self->{count}++;
}
sub sum {
my $self = shift;
my $sum = $self->count;
$sum = $sum == 1 ? $sum . ' TIME ' : $sum . ' TIMES ';
return $sum;
}
sub persons {
my $self = shift;
my $people = '';
my @people = @{$self->person};
for (0..$#people) {
$people .= $_ != $#people ?
uc ($people[$_]) . ' and ' :
uc ($people[$_]);
}
return $people;
}
package FruitBox;
use Moose;
has 'fruits' => ( isa => 'HashRef', is => 'rw' );
sub add {
my $self = shift;
die unless @_ == 2;
my $name = shift;
my $person = shift;
if (exists $self->{fruits}->{$name}) {
my $fruit = $self->{fruits}->{$name};
$fruit->add_person($person) and $fruit->inc;
} else {
my $fruit = Fruit->new;
$fruit->add_person($person) and $fruit->inc;
$self->{fruits}->{$name} = $fruit;
}
}
sub to_s {
my $self = shift;
my $text = '';
for my $fruit (sort keys %{$self->{fruits}}) {
my $f = $self->{fruits}->{$fruit};
$text .= uc ($fruit) . ' appears ' . $f->sum .
'associated with ' . $f->persons . "\n";
}
return $text;
}
package main;
my $box = new FruitBox;
while (<DATA>) {
warn $_ and next unless /^(\w+)\s+(\w+)$/;
$box->add($1, $2);
}
print $box->to_s;
__DATA__
apple Tom
orange Tom
pear Tom
mango David
apple David
| [reply] [d/l] |
|
|