2

Can anybody tell me how to push a duplicate element of an array to a new array? This is what I have till now, again I want to retain the duplicate elements into a new array.

%seen = ();
@uniq = ();
foreach $item (@list) {
    unless ($seen{$item}) {
        $seen{$item} = 1;
        push(@uniq, $item);
    }
}
print "@unique\n";
1
  • 6
    Are you trying to find duplicates, as your text says, or are you trying to remove duplicates as your code says? Commented Jul 11, 2012 at 8:19

6 Answers 6

6

Always start your scripts with use strict; and use warnings;.

use strict ;
use warnings ;

my @list = ( 1 .. 10 , 2 , 5 , 6 ) ;

my %seen = ();
foreach my $item (@list) {
  $seen{$item}++ ;
}

my @uniq = grep { $seen{$_} == 1 } keys %seen ;
my @not_unique = grep { $seen{$_} > 1 } keys %seen ;

Simply count each occurrence of the elements in a hash and use a grep afterwards.

Sign up to request clarification or add additional context in comments.

Comments

5

It's unclear what you're trying to accomplish... do you want to remove duplicates, or find them? Here's a solution for either:

To remove duplicates

use strict;
use warnings;

my @list = (1,2,3,4,5,6,1,2,3);

my %unique;
@unique{ @list } = ();
print join(',',sort keys %unique)."\n";

Output:

1,2,3,4,5,6

To grab only duplicates

use strict;
use warnings;

my @list = (1,2,3,4,5,6,1,2,3);

my %dupes;
%dupes = map { $_ => $dupes{$_}++ } @list;
delete @dupes{ grep { $dupes{$_} == 0 } keys %dupes };
print join(',',sort keys %dupes)."\n";

Output:

1,2,3

2 Comments

sub uniq { my %seen; grep ! $seen{$_}++, @_ } will maintain the order of the list, as will sub dupe { my %seen; grep $seen{$_}++, @_ }
@Zaid: A nice addition. Thanks!
3

If you're trying to find values that appear more than once:

my @seen;
my @dups = grep ++$seen{$_} == 2, @list;

@list = qw( foo bar baz foo foo moo bar );
  gives
@dups = qw( foo bar );

If you're trying to put the values that are only found once in @uniq and values that are found twice or more in @dups:

my %counts; 
++$counts{$_} for @list;

my (@uniq, @dups);
for (@list) {
   my $count = $counts{$_};
   push @uniq, $_ if $count == 1;
   push @dups, $_ if $count == 2;
}

@list = qw( foo bar baz foo foo moo bar );
  gives
@uniq = qw( baz moo );
@dups = qw( foo bar );

If you're trying to put the first instance of a value in @uniq and the second and subsequent values in @dups:

my (@uniq, @dups, %seen);
push @{ $seen{$_}++ ? \@dups : \@uniq }, $_ for @list;

@list = qw( foo bar baz foo foo moo bar );
  gives
@uniq = qw( foo bar baz moo );
@dups = qw( foo foo bar );

Comments

3

Same logic as yours, but different statements.

use strict;
my @ar = (1,2,3,4,1,2);
my %ar = map { $_ ,  1 } @ar ;
my @ar1 = keys %ar;

print @ar1;

Also check this

Comments

2

Eliminating duplicates is this simple:

use List::MoreUtils qw<uniq>;

my @uniq = uniq @list;

Getting duplicates, requires a little more explicit Perl:

my %seen;
my @dups = grep { ++$seen{ '' . $_ } == 2 } @list;

Comments

2

You must always use strict and use warnings at the start of your programs, and declare all variables using my at their point of first use. In this case it would have shown you that you were addaing data to the array @uniq but displaying the contents of @unique.

This program will print a list of all unique data items, and a second list of data that has occurred twice or more

use strict;
use warnings;

my @list = qw/ a a a b b c /;

my %seen;
my @uniq;
my @multiple;

foreach my $item (@list) {
  if (not $seen{$item}++) {
    push @uniq, $item;
  }
  elsif ($seen{$item} == 2) {
    push @multiple, $item;
  }
}
print "Unique: @uniq\n";
print "Multiple: @multiple\n";

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.