Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Fast Way to Return Unique Array of Array

by neversaint (Deacon)
on Sep 05, 2005 at 03:00 UTC ( [id://489127]=perlquestion: print w/replies, xml ) Need Help??

neversaint has asked for the wisdom of the Perl Monks concerning the following question:

Dear Masters,
I am trying to find unique array of Array with this code:
use List::MoreUtils qw/uniq/; my @AoA = (['a','b','c'], ['a','b','c'], ['a','b','d'], ['a','b','d']); my @uAoA = uniq(@AoA); print Dumper \@uAoA;
But it fails to return the desired result:
$VAR1 = [ ['a','b','c], ['a','b','d'] ];
Why is it? Is there a quick way to achieve that?

---
neversaint and everlastingly indebted.......

Replies are listed 'Best First'.
Re: Fast Way to Return Unique Array of Array
by pg (Canon) on Sep 05, 2005 at 03:30 UTC

    This is not what the function is supposed to do. Take a look at the source code. It only understands the first level of your AoA. Copy and paste, modify a little bit:

    use Data::Dumper; my @AoA = (['a','b','c'], ['a','b','c'], ['a','b','d'], ['a','b','d']); my @uAoA = uniq(@AoA); sub uniq () { #updated, the prototype was taken out my %h; map { $h{$_}++ == 0 ? $_ : () } @_; print Dumper \%h; }

    Run it , you get print out similar to this:

    $VAR1 = { 'ARRAY(0x224ff8)' => 1, 'ARRAY(0x18c3a2c)' => 1, 'ARRAY(0x1875904)' => 1, 'ARRAY(0x224ef0)' => 1 };

    Now it is obvious, all those four elements of the LIST are different and uniqe, and that's why the entire original AOA is returned.

    Update:

    Just to extend a little bit. uniq will work with this code, base on the way the AoA is formed. The input AoA is logically equal to your AoA. And the output is now the same as what you wanted. (I am not saying that this is a solution for you, as you probably cannot form your data like this or cannot do it easily. This only demos the nature of uniq(). )

    use Data::Dumper; use List::MoreUtils qw(uniq); use strict; use warnings; my $a = ['a','b','c']; my $b = ['a','b','d']; my @AoA = ($a, $a, $b, $b); my @uAoA = uniq(@AoA); print Dumper(\@uAoA);

    Why does it work? Because the uniq function sees two uniq array refs.

Re: Fast Way to Return Unique Array of Array
by Zaxo (Archbishop) on Sep 05, 2005 at 03:32 UTC

    The array references in @AoA are to four distinct locations, so they are all unique, even though their contents may be equal.

    We've shown you a bunch of ways to get uniqueness, mostly having to do with hash keys. You can form a suitable key from one of these array references with join ',', @{$AoA[$idx]}.

    After Compline,
    Zaxo

Re: Fast Way to Return Unique Array of Array
by GrandFather (Saint) on Sep 05, 2005 at 04:09 UTC

    This may be what you are trying to achieve, though it's not very pretty:

    use strict; use warnings; use List::Compare::Functional qw(is_LequivalentR); use Data::Dumper; my @AoA = (['a','b','c'], ['a','b','c'], ['a','b','d'], ['a','b','d']); my @uAoA; skip: for my $ia (0..(@AoA-1)){ for my $ir (0..(@uAoA-1)){ next skip if is_LequivalentR ([\@{$AoA[$ia]}, \@{$uAoA[$ir]}]); } push @uAoA, [@{$AoA[$ia]}]; } print Dumper \@uAoA;

    Outputs:

    $VAR1 = [ [ 'a', 'b', 'c' ], [ 'a', 'b', 'd' ] ];

    Perl is Huffman encoded by design.
Re: Fast Way to Return Unique Array of Array
by monkfan (Curate) on Sep 05, 2005 at 03:58 UTC
    This is not a neat code, but does the job. Inspired from good Zaxo's comment to you above:
    #!/usr/bin/perl -w use strict; use Data::Dumper; my $uAoA = uniqAoA(\@AoA); print Dumper $uAoA; sub uniqAoA { my $array = shift; my %res; foreach my $ar (@{$array}) { my $str = join (",",@{$ar}); $res{$str} = 1; } my @kys = keys(%res); my @final; foreach(@kys) { my @a = split(",",$_); push @final, [ @a ]; } return \@final; }

    Regards,
    Edward

      There are some risks here: (I can easily come up some data to make this fail.)

      use strict; use Data::Dumper; my @AoA = (['a,','b','c'], ['a',',b','c'], ); my $uAoA = uniqAoA(\@AoA); print Dumper $uAoA; sub uniqAoA { my ($array) = @_; my %res; foreach my $ar (@{$array}) { my $str = join (",",@{$ar}); $res{$str} = 1; } my @kys = keys(%res); my @final; foreach(@kys) { my @a = split(",",$_); push @final, [ @a ]; } return \@final; }

      This should return the orginal AoA, but it returns:

      $VAR1 = [ [ 'a', '', 'b', 'c' ] ];

      Problems are:

      • It thought the two level 2 arrays are the same, when they are different.
      • The element contained in the returned array was not originally there.
        Hi pg,
        my @AoA = (['a,','b','c'], ['a',',b','c'], );
        Your example above is problematic: Shouldn't it be this:
        my @AoA = (['a','b','c'], ['a','b','c'], );
        With the latest modification of your example my code still return the correct answer.

        Regards,
        Edward
Re: Fast Way to Return Unique Array of Array
by TedPride (Priest) on Sep 05, 2005 at 06:21 UTC
    Just set $delim to whatever character or sequence of characters is not going to be found inside any of your nested array fields. I used tabs.
    use strict; use warnings; use Data::Dumper; my @AoA = (['a','b','c'], ['a','b','c'], ['a','b','d'], ['a','b','d']); my (%h, @uAoA); for (@AoA) { push @uAoA, $_ if !$h{join $;, @$_}++; } print Dumper \@uAoA;
    EDIT: Edited code to use $;, as per suggestion.
      nice solution, but better to use $; instead of $delim IMHO.... see perlvar manpage.
Re: Fast Way to Return Unique Array of Array
by pg (Canon) on Sep 05, 2005 at 07:16 UTC

    Slightly modify the original uniq(), it works:

    use Data::Dumper; my @AoA = (['a','b','c'], ['a','b','c'], ['a','b','d'], ['a','b','d']); my @uAoA = uniq(@AoA); print Dumper \@uAoA; sub uniq () { my %h; map { $h{join($;, @$_)}++ == 0 ? $_ : () } @_; }

      Nice, just a slight style improvement:

      map { $h{join($;, @$_)}++ == 0 ? $_ : () } @_;

      becomes

      grep { ! $h{join($;, @$_)}++ } @_;
        Could one replace join($;, @$_) with Dumper($_) (or some variant thereof), to allow for multiple levels of data structure?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://489127]
Approved by davido
Front-paged by monkfan
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (5)
As of 2024-03-19 06:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found