Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Counting Data in two columns?

by sdslrn123 (Novice)
on Jun 15, 2006 at 00:01 UTC ( [id://555383]=perlquestion: print w/replies, xml ) Need Help??

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?

Replies are listed 'Best First'.
Re: Counting Data in two columns?
by ikegami (Patriarch) on Jun 15, 2006 at 00:13 UTC
      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?
        #!/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;
      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

        The easiest way is to convert

        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); } }
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 )
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
Re: Counting Data in two columns?
by neniro (Priest) on Jun 15, 2006 at 10:32 UTC
    If you like OOP(erl):
    #!/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

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://555383]
Approved by ikegami
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others scrutinizing the Monastery: (1)
As of 2024-04-25 04:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found