Richard
Richard

Reputation: 3100

Perl Algorithm:Permute and List::AllUtils (uniq)

use Modern::Perl;
use Algorithm::Permute;
use List::AllUtils qw/uniq/;

find_perms(1151);

sub find_perms { 
  my ($value) = @_;
  my @others;
  my @digits = split(//, $value);

  my $perm = Algorithm::Permute->new( \@digits );

  while (my @next = $perm->next()) { 
    my $number = join('', @next);
    push @others, $number;
  }
  @others = sort uniq @others;

  # this one works correctly
  # @others = sort ( uniq( @others ));

  say "FOUND @others";
}

Output:
FOUND 1115 1115 1115 1115 1115 1115 1151 1151 1151 1151 1151 1151 1511 1511 1511 1511 1511 1511 5111 5111 5111 5111 5111 5111

Hi,

After discovering out that Algorithm::Permute is producing duplicates, most likely due to the amount of '1's in "1151" i decided to use uniq. However using sort uniq without the parenthesis doesn't produce expected results. But sort(uniq(@x)) does. What gives?

Upvotes: 4

Views: 191

Answers (3)

ikegami
ikegami

Reputation: 385829

Algorithm::Loops's NextPermute doesn't produce duplicates, so there's no need to spend memory and CPU getting rid of them.

use Algorithm::Loops qw( NextPermute );

sub find_perms { 
   my @rv;
   my @digits = sort split //, $_[0];
   do {
      push @rv, join '', @digits;
   } while NextPermute(@digits);
   return @rv;
}

say for find_perms(1151);

1115
1151
1511
5111

Upvotes: 5

Sinan Ünür
Sinan Ünür

Reputation: 118128

While @mob answered the question you asked, I would like to point out I am not sure if you want to go the sort uniq way. You are still storing elements you don't really want to store. In such cases, it is best to use a hash.

Also, please, when a piece of data is meant to be a string, use a string. The output from find_perms(0345) may surprise you, but find_perms('0345') won't.

Finally Algorithm::Permute::permute is very fast.

With those considerations in mind, I would re-write your code as:

use strict; use warnings;
use Algorithm::Permute qw( permute );

my $uniq_perms = find_perms('115122345');

sub find_perms {
  my ($value) = @_;

  my @digits = split //, $value;
  my %uniq;

  permute { $uniq{join('', @digits)} = undef } @digits;

  return [ keys %uniq ];
}

Upvotes: 4

mob
mob

Reputation: 118605

perldoc -f sort lists three syntaxes for the sort function:

sort SUBNAME LIST
sort BLOCK LIST
sort LIST

sort uniq @others matches the sort SUBNAME LIST syntax of sort. It expects uniq to be a function that compares the global variables $a and $b, and returns <0, 0, or >0 to indicate the relative ordering of $a and $b.

It looks like you were expecting and wanting the sort LIST syntax, which is what you get when you say one of

sort(uniq(@others))
sort(uniq @others)

Upvotes: 6

Related Questions