TheYoungMonk has asked for the wisdom of the Perl Monks concerning the following question:

Greetings to all honoured monks!

I have written a particular piece of code for detecting multiple occurences of an element in an array. It also deletes all repeating occurences of such elements. In a haste, i coded it in the "traditional way" (using for loop, if...).

But now curious to exploit the powers of PERL..Does PERL provide any other way by which i can do the same operation in a more optimized way ?

Can the holy monks please help me exploit the hidden powers of PERL?

  • Comment on Optimize - Checking multiple occurences of elements in an array

Replies are listed 'Best First'.
Re: Optimize - Checking multiple occurences of elements in an array
by thinker (Parson) on Jan 23, 2003 at 15:54 UTC
    Hi TheYoungMonk,

    The idiomatic way to count repeat values, or select unique values from an array is by using a hash.
    for example
    #!/usr/bin/perl -w use strict; my @arr=(1,3,5,2,6,3,7,4,9,2,3,5,1,7); my %count; $count{$_}++ for @arr; print "$_ occured $count{$_} times\n" for sort { $count{$b} <=> $count +{$a} || $a <=> $b} keys %count; my @uniq = sort keys %count; print "\nunique values are @uniq\n"

    this will produce
    3 occured 3 times 1 occured 2 times 2 occured 2 times 5 occured 2 times 7 occured 2 times 4 occured 1 times 6 occured 1 times 9 occured 1 times unique values are 1 2 3 4 5 6 7 9

    hope this helps

    thinker
Re: Optimize - Checking multiple occurences of elements in an array
by hardburn (Abbot) on Jan 23, 2003 at 15:18 UTC

    You can use map() to iterate over the array. You can use this to build a hash that has only unique elements:

    my @a = (0, 1, 1, 2, 3, 4, 5, 5, 5, 6); my %unique; map { $unique{$_} = 1 } @a; my @a_unique = keys %unique;

    Above is untested, as always.

    If you want to put the data back in sorted order, change the last line to:

    my @a_unique = sort { $a <=> $b } keys %unique;

    I can't really get more specific without knowing what exactly you are doing, but this should give you some ideas.

Re: Optimize - Checking multiple occurences of elements in an array
by boo_radley (Parson) on Jan 23, 2003 at 16:11 UTC
    Can the holy monks please help me exploit the hidden powers of PERL?
    See perlfaq 4, "How can I remove duplicate elements from a list or array?" under the section named "Data:Arrays"
A more complete Unique()
by dragonchild (Archbishop) on Jan 23, 2003 at 18:14 UTC
    An interesting note was made in the Chatterbox about how the idiomatic way of deleting duplicates won't work if you have both undef and the empty string ("") as values. This is because stringification treats them both the same.

    It also won't work for an array of references, for the same reason. (It won't work for an ordered array for a different reason.)

    In the spirit of fixing both issues, I offer the following:

    sub unique (@) { my ($arr) = shift; my %x; for my $index (0 .. $#$arr) { my $val = $arr->[$index]; !defined($val) && do { $x{__NOT_DEFINED__} ||= [ $index, undef, ]; next; }; $x{$val} ||= [ $index, $val, ]; } map { $_->[1] } sort { $a->[0] <=> $b->[0] } values %x; }

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      Very complicated and breaks if a literal __NOT_DEFINED__ appears in the input data. Contrary to the posts so far, the standard idiom is not just using a hash, but combining it with grep:
      my %seen; my @unique = grep !$seen{$_}++, @array;
      This retains order and does not break references. It does have the problem with empty strings vs undefs cancelling each other away when they (probably) shouldn't, but that's easily fixed:
      my (%seen, $seen_undef); my @unique = grep defined ? !$seen{$_}++ : !$seen_undef++, @array;

      Makeshifts last the longest.

Re: Optimize - Checking multiple occurences of elements in an array
by Mr. Muskrat (Canon) on Jan 23, 2003 at 16:29 UTC
      See What's the difference between "perl" and "Perl"? in perlfaq1.