vc_will_do has asked for the wisdom of the Perl Monks concerning the following question:
Hi Monks, I have an array
@array = (1,1,3,3,2,3,5,7,5,2);
Is there a way to remove repeating values and make the array
@array = (1,3,2,5,7);
Order of elements is NOT a big concern as I am going to sort in next step.
Thanks In Advance
Re: Remove redundency from an array
by oha (Friar) on Sep 24, 2007 at 10:45 UTC
|
| [reply] |
Re: Remove redundency from an array
by marto (Cardinal) on Sep 24, 2007 at 10:45 UTC
|
| [reply] |
Re: Remove redundency from an array
by ForgotPasswordAgain (Priest) on Sep 24, 2007 at 10:57 UTC
|
| [reply] [d/l] |
Re: Remove redundency from an array
by bruceb3 (Pilgrim) on Sep 24, 2007 at 10:47 UTC
|
#!/usr/bin/perl
use strict; use warnings;
use Data::Dumper;
my @array = (1,1,3,3,2,3,5,7,5,2);
my %h;
$h{$_}++ for @array;
@array = keys %h;
print Dumper \@array;
| [reply] [d/l] |
|
@h{@array} = ( );
A word spoken in Mind will reach its own level, in the objective world, by its own weight
| [reply] [d/l] [select] |
|
Bruce and jd's solution are both fine and far less ugly than the FAQ. Is there a reason these solutions aren't on there and the FAQ version is using splice?
| [reply] |
|
|
Re: Remove redundency from an array
by lyklev (Pilgrim) on Sep 24, 2007 at 19:33 UTC
|
Most of the answers given involve a hash, which is a good idea; the reason for this is that arrays are good for storing, but not for looking up information - hashes are much better suitable for that. You might want to redesign your program slightly, so you store your information in a hash to start with.
However, since you will be sorting the array, there might be a different approach: first sort it, and since it is sorted, remove duplicate elements, which, because of the sorting, will be sequential.
use strict;
use warnings;
my @array = (1,2,5,6,4,2,1,2,3,4,6,4,3,2,4,6,6);
my @sorted = sort {$a <=> $b} @array; # numerically
@array = (sort shift @sorted); # overwrite old array
while (my $element = shift @sorted) {
# if the element differs from the last added, keep it
# otherwise discard
if ($element != $array[-1]) {
push (@array, $element);
}
}
# array is now sorted, no duplicate elements
| [reply] [d/l] |
|
The idea is sound. Depending on how many duplicates there are, it may end up more expensive (since you're sorting the entire array, instead of only the unique items). Also, the line @array = (sort shift @sorted) is really...odd. Why not just @array = shift @sorted? Additionally, I think instead of while (my $element = shift @sorted) { I would have just used for (@sorted){, unless there's a reason you really want to destroy the sorted version as you go.
| [reply] [d/l] [select] |
|
You are right, it should have been just
@array = (shift @sorted)
(the parentheses are to make it an array assignment).
If there are many duplicates it might be more efficient to first remove the duplicates before sorting. But there is no transforming the array into a hash and back.
I can't tell which is more efficient. My intention was to show a different approach. It shows again that there are many ways to do similar things.
| [reply] [d/l] |
Re: Remove redundency from an array
by mwah (Hermit) on Sep 24, 2007 at 14:20 UTC
|
This is, as has shown here, a fairly
often used and well documented task.
Sometimes I'd use snippet that reads like
my @array = (1,1,3,3,2,3,5,7,5,2);
# uniqify without modules
@array = do { @$_{@array} = (); keys %$_ };
Regards
M.
| [reply] [d/l] |
|
local *_;
at the beginning of that do block.
| [reply] [d/l] [select] |
|
jdporter: Of course, that clobbers $_. Perhaps you want to insert local *_; ...
Would this (*_) be relevant here?
$_ *might* be localized, but *_ imho not.
consider:
sub uinq {
# local *_; # <== will fail, $_ will work
@_ = do { @$_{@_}=(); keys %$_ }; @_
}
my @array = (1,1,3,3,2,3,5,7,5,2);
print "@{[ uinq @array ]}\n";
Regards & thanks mwa
| [reply] [d/l] [select] |
|
|
|
|
|
| [reply] [d/l] |
Re: Remove redundency from an array
by gube (Parson) on Sep 24, 2007 at 15:02 UTC
|
This below code also one of the method to avoid duplicate values from array. It's lengthy code, However, it's one of the alternate method.
my @array = (1,1,3,2,3,5,3,3,7,5,2);
my (%ar_hash, @ar);
for(@array) {
next if($ar_hash{$_}++);
push(@ar, $_);
}
print "@ar";
o/p : 1 3 2 5 7
| [reply] [d/l] |
|
my @u = do { my %seen; grep { ! $seen{$_}++ } @a };
| [reply] [d/l] |
|
|