Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?

by memnoch (Scribe)
on Nov 29, 2007 at 21:30 UTC ( [id://653982]=perlquestion: print w/replies, xml ) Need Help??

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

UPDATE: Thank you all for your suggestions! I'm all set!
memnoch

Venerated Monks,

I'm wondering if there is a clever way to assign unique values to a simple array without having to loop through the array for each value to be considered. In my situation, there is no way to tell the array position that the possible value might beforehand, so I can't use an index.

As an alternative, I have tried using a hash instead, like so:
my $test; unless (exists($hash{$test})) { $hash{$test} = "dummy"; # Don't care about the value }
That way, I get unique values. But when I try to retrieve the values with:

keys(%hash)

I'm not guaranteed to get them in the order that I inserted them. The inserted order is preferred but not essential. Any ideas?

Thank you,
memnoch
Gloria in Excelsis Deo!
  • Comment on Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
  • Select or Download Code

Replies are listed 'Best First'.
Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by friedo (Prior) on Nov 29, 2007 at 21:37 UTC
    You can create an ordered hash with Tie::IxHash. Or you can filter duplicates using List::MoreUtils's uniq function. (Which basically just uses a hash to do it anyway.) But I think perhaps you're making the problem more complicated than it needs to be. If you describe in more detail what it is you're trying to accomplish, we might be able to offer better solutions.
      Thank you friedo! Actually, I just realized that I could do something like:
      my $test; unless (exists($hash{$test})) { $hash{$test} = localtime; # For sorting later on }
      Then I can do:

      sort keys(%hash)

      to get the keys in the inserted order.....I'll have to test it later.

      memnoch

      Gloria in Excelsis Deo!

        I'd suggest using a counter variable rather than localtime (did you mean time?).

        my $count = 0; my $test; unless ( exists $hash{$test} ) { $hash{$test} = $count++; }

        This way, you can be sure you don't have duplicate values in the hash, even if you insert two elements at the same second.

        To do the sorting, you'd need to do this:

        sort { $hash{$a} <=> $hash{$b} } keys %hash;
Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by Skeeve (Parson) on Nov 29, 2007 at 21:58 UTC
    If you don't want to use a tied hash, you can use an array and a hash. The hash to see whether or not a value has been seen and the array to store the values in order.
    push(@array, $value) unless $seen{$value}++

    s$$([},&%#}/&/]+}%&{})*;#$&&s&&$^X.($'^"%]=\&(|?*{%
    +.+=%;.#_}\&"^"-+%*).}%:##%}={~=~:.")&e&&s""`$''`"e
      Thanks Skeeve! I tried your code and see that it works, but I don't understand how the

      unless $seen{$value}++

      works with the autoincrement. Is there an explanation you could point me to?

      memnoch

      UPDATE: Okay, I understand it now....I didn't realize that the autoincrement was assigning a value to the hash key that was incremented each time the code runs into the same key. That's very clever! I'm all set. Thank you!

      Gloria in Excelsis Deo!
Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by traveler (Parson) on Nov 30, 2007 at 00:08 UTC
    Another way to look at this is that you want a shuffled version of some list. Take (1..7) for example. With Algorithm::Numerical::Shuffle you can do that easily:
    @array = shuffle(1..7);
    The idea of shuffling an array has been discussed before (and other places, too).

    HTH, --traveler

Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by Fletch (Bishop) on Nov 29, 2007 at 21:37 UTC

    Use Tie::IxHash to maintain insertion order?

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Thanks Fletch!
      memnoch

      Gloria in Excelsis Deo!
Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by dragonchild (Archbishop) on Nov 30, 2007 at 04:23 UTC
    List::MoreUtils uniq() preserves order.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      curiously, (the pure-perl version of) List::MoreUtils::uniq uses
      map { $h{$_}++ == 0 ? $_ : () } @_;
      rather than
      grep { !$h{$_}++ } @_;
      i wonder, a simple preference or are there interesting micro-optimizations in the map verison?
        I have no idea. If I were to guess, I would say that it probably has to do with a bug report that was received for 5.6.0 on some random OS we've never heard of. Lack of comments make this unclear.

        My criteria for good software:
        1. Does it work?
        2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by mreece (Friar) on Nov 30, 2007 at 02:26 UTC
    if i understand correctly, you can do it with an intermediate hash and grep.
    my %seen; my @nodupes = grep { not $seen{$_}++ } @mayhavedupes;
    as for whether you consider grep "having to loop" or not, well, it's a lot less loopy than sorting keys...
Re: Is there an easy way to assign guaranteed unique values to a simple array without looping through whole array?
by aquarium (Curate) on Nov 30, 2007 at 00:10 UTC
    there's also a pseudohash in perl...when a particular condition is met (i forget what this is) then the array can be treated as either an array or hash as needed.
    the hardest line to type correctly is: stty erase ^H

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-04-24 15:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found