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

Dear all,

lets say I have an array of IDs that look like this:

(A1,A2,A3,B5,B6,B7,C789,C790)

etc. etc.

What I want to do is to slurp this array into another one, where ALL I have is one example of each letter.

So I want my final array to be:

(A,B,C) (sorted too)

So, i was kind of thinking along the lines of:

my @substringedarray = sort {$a <=> $b} grep {substr($_,0,1)} @origina +l array;

will this work?

Cheers
Sam

Replies are listed 'Best First'.
Re: slurping into a substring'ed' array
by broquaint (Abbot) on Apr 26, 2004 at 15:13 UTC
    That should work, but if you want a unique array then hashes will be the simplest way to go e.g
    my @ids = qw/ A1 A2 A3 B5 B6 B7 C789 C790 /; my @letters = sort keys %{ { map { substr($_,0,1), undef } @ids } }; print "Found the following letters: @letters\n"; __output__ Found the following letters: A B C
    See. Perl Idioms Explained - keys %{{map{$_=>1}@list}} for an explanation of the above technique for simply getting a unique list.
    HTH

    _________
    broquaint

    update: fixed bug as noted below by davido

      There's a hidden bug in that example. Try running it with a long list of unique alphas and you'll see what I mean. The problem is that in each map iteration you're only creating one item. In your hash assignment, one item is being assigned to the key, and the next to a value. The result is that some letters are being dropped.


      Dave

Re: slurping into a substring'ed' array
by davido (Cardinal) on Apr 26, 2004 at 15:14 UTC
    my %hash = map { substr($_, 0, 1), 1 } @original_array; my @sorted = sort keys %hash;

    Or, less explicitly and without the named temporary hash:

    my @sorted = sort keys %{{map{substr($_,0,1 ),1} @original_array}};

    Both methods are really the same thing; they create a hash in order to guarantee uniqueness of keys, and then use the keys to populate a new array after sorting them.


    Dave

Re: slurping into a substring'ed' array
by dragonchild (Archbishop) on Apr 26, 2004 at 15:11 UTC
    will this work?

    You can answer your own question by trying it, you know ...

    One more thing - you don't want grep, you want map.

    One more thing - you'll probably want to get the list of unique items. Hint - this is a FAQ.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

Re: slurping into a substring'ed' array
by blue_cowdawg (Monsignor) on Apr 26, 2004 at 15:17 UTC

        This will give me an array of ALL the letters, but not the unique letters.

    Here's a rather IMHO long winded way to do it:

    #!/usr/bin/perl -w my @foo=('A1','A2','A3','B5','B6','B7','C789','C790'); my %letters=(); my @muut = map { $letters{substr($_,0,1)}++ } @foo; my @final = sort keys %letters; printf "%s\n",join(",",@final);
    Hope this helps.

      Technically, you don't need the ++. Just by accessing the hash value creates the key. So, you could do something like:
      $letters{substr($_,0,1)} for @foo;

      Though, it is polite to explicitly set it to undef, unless you need the count. :-)

      ------
      We are the carpenters and bricklayers of the Information Age.

      Then there are Damian modules.... *sigh* ... that's not about being less-lazy -- that's about being on some really good drugs -- you know, there is no spoon. - flyingmoose

        Just by accessing the hash value creates the key.
        $letters{substr($_,0,1)} for @foo;
        that gives:
        Useless use of hash element in void context
        besides that, just accessing the hash value does not create it. autovivification only happens if you're accessing an element one level deeper (e.g. in a HoH)
        dear all respondees,

        thanks for your fast responses, i was in the proces of testing it myself, and had got as far as:

        my %seen; my @sorted = sort($a <=> $b) grep{ $seen{$_}++ } map {substr($_,0,1)} +@original_array;

        when i realised y'all were on the board already!!

        I just wanted to point out that my code above printed out this list:

        A,A,B,B,C

        So why did it only print out the extra As and Bs? Out of curiosity.

        Thanks again for your help.

        Sam

Re: slurping into a substring'ed' array
by sgifford (Prior) on Apr 26, 2004 at 17:14 UTC

    If you need to sort them anyways, an easy way to do it is first sort the array. With the array sorted, identical items will be right next to each other, so to eliminate duplicates you only have to check if an item is the same as the one immediately preceding it, and if so delete it (or not add it to the results). That's essentially how the Unix utility uniq(1) works.

    Here's some code I use to do this. It takes a comparison coderef as the first parameter, much like sort, and the array to be sorted and uniqified as the second.

    sub uniq(&@) { my($cmpsub, @list)=@_; my $last = shift @list or return (); my @ret =($last); foreach (@list) { push(@ret,$_) unless sortcmp($cmpsub,$_,$last)==0; $last = $_; } @ret; }

    My suspicion is that doing this will be slightly faster than using a hash for very large arrays, but I haven't measured it.

Re: slurping into a substring'ed' array
by jdporter (Paladin) on Apr 26, 2004 at 17:12 UTC
    sub set_of_initials { my %h; local $" = "\n"; @h{ "@_" =~ /^./sg } = (); sort keys %h } @b = set_of_initials( @a );