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

Re: Add a fixed number of unique elements to hash

by jo37 (Deacon)
on Mar 05, 2023 at 16:56 UTC ( [id://11150759] : note . print w/replies, xml ) Need Help??

in reply to Add a fixed number of unique elements to hash

I would shuffle the list of files and select the first $numOfRandFiles from it, like

use List::Util 'shuffle'; ... (shuffle(@audiofiles))[0 .. $numOfRandFiles - 1];

Note that this generates a list, not a hash.
If you cannot (or don't want to) use a module, you need to reinvent the wheel.



Replies are listed 'Best First'.
Re^2: Add a fixed number of unique elements to hash
by tybalt89 (Monsignor) on Mar 05, 2023 at 21:11 UTC

    There is also this that does the equivalent of shuffle and pick N.

    use List::AllUtils qw( sample ); my @selected = sample $numOfRandFiles, @audioFiles;

      G'day tybalt89,

      When initially writing the code in my response, I checked the List::Util::shuffle() documentation and noticed the sample() function immediately after it. I hadn't encountered that previously and decided to give it a go.

      Curiously, although it did work as documented, multiple runs produced the same results. As you can see from my "sample runs" using shuffle(), multiple runs produced different results (yes, only two runs shown, but I did run it quite a few times).

      Looking at source/lib/List/, List::AllUtils::sample() should be identical to List::Util::sample(). I have List::Util v1.62 and Perl v5.36.0.

      I'm a bit short on time this morning; I was thinking of investigating further this afternoon [Aussie timezone: UTC+11:00]. If you have any insights into the behaviour of sample(), please share.

      It did seem like sample(), taking a random selection from the array, was probably a better choice than shuffle(), randomising the entire array and then taking a slice (obviously, benchmarking needed to confirm this). On the down side, sample() requires List::Util v1.54: you'd need at least Perl v5.32.0 (which has v1.55) or an upgrade from CPAN.

      — Ken

        I have a slightly newer verison of List::Util here (1.63 as below) and sample appears to work as intended, ie. different runs produce different results:

        $ pmv List::Util 1.63 $ perl -MList::Util=sample -wE 'my @x=("a".."z"); say sample (3, @x)' jso $ perl -MList::Util=sample -wE 'my @x=("a".."z"); say sample (3, @x)' ter $ perl -MList::Util=sample -wE 'my @x=("a".."z"); say sample (3, @x)' mgl $ perl -MList::Util=sample -wE 'my @x=("a".."z"); say sample (3, @x)' ago $

        There's nothing in the List::Util changelog to indicate any modification to sample so either some other fix has had an effect or something else is at play.


        Many thanks for your replies and testing, but the target machine is running Perl 5.004 (unfortunately I wasn't precise enough when I just wrote Perl 5). The final solution was to use splice as suggested by jwkrahn in the next post.

      Be careful with List::AllUtils. "All" isn't really "all". At least frequency from List::MoreUtils is missing. I prefer to use the original modules.



        Probably because of

        use List::AllUtils qw( count_by ); %frequencies = count_by { $_ } LIST;
Re^2: Add a fixed number of unique elements to hash
by jwkrahn (Abbot) on Mar 05, 2023 at 22:02 UTC

    If shuffle takes too long you could do this:

    sub uploadPlaylist { for my $i ( 1 .. $numOfRandFiles ) { $playList{ splice @audioFiles, int rand @audioFiles, 1 } = $i; } }
    Naked blocks are fun! -- Randal L. Schwartz, Perl hacker
      Thx a lot jwkrahn! Splice is the key for me. Other solutions that use "factory" modules are out of the question, i.e. this machine is running perl 5.004, which has quite a few syntactical differences compared to today's perl versions. Of course, I could try transplanting the modules, but my only connection to this old SGI machine is via nfs sharing over a software half-speed network interface (since it can no longer be communicated with securely with today's settings).