This code will return a unique array such that "print &ua(a,a,a,b,b,c)" will print "abc".
sub ua{grep(!$h{$_}++,@_);}

Replies are listed 'Best First'.
RE: Return a Unique Array
by sergio (Beadle) on Feb 25, 2000 at 19:44 UTC
    GrassHopper! Always read the books. In the Perl Cookbook you can find
    
    my %seen =() ;
    @unique_array = grep { ! $seen{$_}++ } @non_unique_array ;
    
    
    Which makes the soul happier!
RE: Return a Unique Array
by Anonymous Monk on Mar 23, 2000 at 21:05 UTC
    Using hashes can take up a lot of memory, especially with long lists. Here's one that acts like sort -u :
    my @list = sort(@list); my @unique; my $i=0; $unique[0] = $list[0]; foreach my $item(@list) { unless($item eq $unique[$i]) { push(@unique,$item); $i++; } }
    @unique is now a sorted unique list.

    Edit kudra, 2001-09-10 Added code tags

      That's nice. Although it is slower than using a hash. Comparing your code against this routine:
      sub sort_unique_hash { my %hash; @hash{@_} = (); return sort keys %hash; }
      gives (where "foreach" is your code and "hash" is the above):
      Benchmark: timing 100000 iterations of foreach, hash... foreach: 14 secs (13.50 usr 0.00 sys = 13.50 cpu) hash: 6 secs ( 5.85 usr 0.00 sys = 5.85 cpu)
      This is with:
      @list = qw/foo bar baz foo quack bar baz/;
      The difference is even more marked if you have rather odd arrays that you want to sort -u. For example, running the code against this array:
      @list = ('foo') x 1000;
      gives
      Benchmark: timing 1000 iterations of foreach, hash... foreach: 12 secs (11.82 usr 0.00 sys = 11.82 cpu) hash: 1 secs ( 0.88 usr 0.00 sys = 0.88 cpu)
      Presumably because your code sorts the list before it selects only the unique elements, and the hash approach only sorts the unique list--so you're sorting 1000 elements, and the hash approach just sorts 1.

      Just something to think about.

      Should be: my $i=1 otherwise you overwrite the first element and are then missing the first element.
        Oops, no it shouldn't, my mistake. $i=0 is correct.
RE: Return a Unique Array
by Anonymous Monk on Feb 04, 2000 at 18:01 UTC
    Trying again with HTML tags... You can achieve the same effect by creating hash keys (they must be unique) then assigning the keys to an array. Ie:
    <<<<<<<<<<<<<<<<<
    
    my ($char,%hash) ;
    
    my (@nonuniquearray) = (a,a,b,c,c,d,e,f) ;
    
    for $char (@nonuniquearray) {
    
            $hash{$char} =1 ;
    }
    
    my (@uniquearray) = keys(%hash) ;
    
    >>>>>>>>>>>>>>>>>>>
    
    - James
      I like to use:
      for (@array) { $foo{$_}++ }; @unique = (keys %foo);
      ...which also allows me to count occurances of different values:
      $applecount = %foo{'apple'};
RE: Return a Unique Array
by Anonymous Monk on Mar 25, 2000 at 01:30 UTC
    I actually wrote 2 of my own. Neither use a hash, but I'm really impressed with the first one that uses only one line. Anyway, here are both of mine:
    sub unique1 { for ($i=$#_;$i>=0;$i--){ my @rest = @_; my $test = splice(@rest,$i,1); if (grep($_ eq $_[$i],@rest)){@_ = @rest}; } return @_; } sub unique2 { foreach $test (@_){ my $i = -1; @indexes = map {$i++;$_ eq $test ? $i : ()} @_; shift @indexes; foreach $index (@indexes){ splice(@_,$index,1); } } return @_; }
    The second one works by removing all the things that are duplicates. The second one works by not adding things that are duplicates. Depending on your array, one might be better than the other.

    An important thing to remember is that when you make a unique array, you might want to preserve the order. Both of mine do, and so does the original one. Using keys with a hash does not preserve order.

A reply falls below the community's threshold of quality. You may see it by logging in.