Re: unique elements in an array
by tall_man (Parson) on Feb 23, 2005 at 16:28 UTC
|
If you want to keep the items in order by first appearance, try using a side hash as an insertion guard.
use strict;
my %guard;
my @unique;
while (<>) {
chomp;
push @unique,$_ if (!exists $guard{$_});
$guard{$_} = 1;
}
print join(" ",@unique),"\n";
| [reply] [d/l] |
|
|
Good code. A few optimizations:
use strict;
my %guard;
my @unique;
while (<>) {
chomp;
next if exists $guard{$_};
push @unique,$_;
$guard{$_} = undef;
}
print join(" ",@unique),"\n";
A slight improvement in speed and memory usage, especially when you are dealing with a large number of duplicates.
Being right, does not endow the right to be rude; politeness costs nothing. Being unknowing, is not the same as being stupid. Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence. Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.
| [reply] [d/l] |
Re: unique elements in an array
by davido (Cardinal) on Feb 23, 2005 at 17:41 UTC
|
use Array::Unique;
tie @a, 'Array::Unique';
@a = qw(a b c a d e f);
push @a, qw(x b z);
print "@a\n"; # a b c d e f x z
The POD states: "This package lets you create an array which will allow only one occurrence of any value. In other words no matter how many times you put in 42 it will keep only the first occurrence and the rest will be dropped."
There is also japhy's Tie::Array::Unique. It behaves a little differently, but is also more configurable, allowing for case-insensitive matching, etc.
| [reply] [d/l] |
Re: unique elements in an array
by JediWizard (Deacon) on Feb 23, 2005 at 16:24 UTC
|
You could use grep to determine if the element already exists in the array. However it may be easier to use a hash. If the items you are working with are simple scalars (aka not references) assigning them as keys in a hash will assure you end up with a unique list. If you do not want to go that way, I have a few standard subroutines I use to find unique elements from a list. One (which is faster) will only work for simple string values, the second will work even when the list contains references. Here they are:
#_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
+-_-_-_-_
# Function: uniqStrings()
# Author: Dave Mueller
# Returns: @uniq
# Parameters: @array
# Description: Returns a unique list of all Strings found in @array
# Note: references wil be broken . . .
#_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
+-_-_-_-_
sub uniqStrings
{
my %temp = ();
@temp{@_} = ();
return keys %temp;
}
#_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
+-_-_-_-_
# Function: uniqValues()
# Author: Dave Mueller
# Returns: @uniq
# Parameters: @array
# Description: Returns a unique list of all values found in @array
#_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
+-_-_-_-_
sub uniqValues
{
my %temp = ();
@temp{@_} = (0 .. $#_);
return map({$_[$_]} values %temp);
}
May the Force be with you
| [reply] [d/l] |
Re: unique elements in an array
by holli (Abbot) on Feb 23, 2005 at 17:44 UTC
|
As others have stated, the hash is the way to go here.
If you are concerned about order, there are modules that keep care of that:
There is also Tie::Array::Unique which sounds promising, but itīs version 0.01 and I never used it.
| [reply] |
Re: unique elements in an array
by artist (Parson) on Feb 23, 2005 at 16:29 UTC
|
Use hash. If you have existing array, convert that into a hash and convert back to array for any purpose served better with array.
(Order may be altered in following case, if that's ok.)
@array = (1,2,3,4);
%hash = map { $_, 1} @array;
@new_elements = (1,3,5,7,9);
$hash{$_} = 1 for @new_elements;
@array = keys %hash;
| [reply] [d/l] |
Re: unique elements in an array
by RazorbladeBidet (Friar) on Feb 23, 2005 at 17:12 UTC
|
#!/usr/bin/perl -w
use strict;
my @start_array = qw( 1 2 3 4 1 4 9 6 17 2 8 );
my %holding_hash;
my @end_array = grep {!$holding_hash{$_}++} @start_array;
print $_, "\n" for @end_array;
--------------
It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
| [reply] [d/l] |
Re: unique elements in an array
by injunjoel (Priest) on Feb 23, 2005 at 19:57 UTC
|
| [reply] |
Re: unique elements in an array
by perlfan (Parson) on Feb 23, 2005 at 18:25 UTC
|
I just run a check using something like:
my @set = qw(1 2 3 4 5 6);
my @add_to_set = qw(5 6 7 8 9);
# note dupes.........^ ^....
foreach (@add_to_set) {
if (!is_member($_,@set) {
push(@set,$_);
} else {
warn "duplicate member detected...\n";
}
}
sub is_member {
my $self = shift;
my $test = shift;
my $ret = 0;
foreach (@_) {
if ($test eq $_) {
$ret++;
last;
}
}
return $ret;
}
As far as I know, there are no native set functions like intersect, union, etc, but these can be easily created with what is available. | [reply] [d/l] |