I want to do the inverse of sort(1) : randomize every line of stdin to stdout in Perl.
Asked
Active
Viewed 2,307 times
3
-
2GNU coreutils' shuf [http://www.gnu.org/software/coreutils/manual/html_node/shuf-invocation.html] does exactly this, but in C. – Steve Schnepp May 25 '09 at 08:06
3 Answers
10
I bet real Perl hackers will tear this apart, but here it goes nonetheless.
use strict;
use warnings;
use List::Util 'shuffle';
my @lines = ();
my $bufsize = 512;
while(<STDIN>) {
push @lines, $_;
if (@lines == $bufsize) {
print shuffle(@lines);
undef @lines;
}
}
print shuffle(@lines);
Difference between this and the other solution:
- Will not consume all the input and then randomize it (memory hog), but will randomize every $bufsize lines (not truly random and slow as a dog compared to the other option).
- Uses a module which returns a new list instead of a in place editing Fisher - Yates implementation. They are interchangeable (except that you would have to separate the print from the shuffle). For more information type perldoc -q rand on your shell.

Vinko Vrsalovic
- 330,807
- 53
- 334
- 373
-
Why do you use $current? Why would you manually maintain the length of the array when the array already knows this? – Leon Timmermans Nov 13 '08 at 12:55
-
-
I think you want if (@lines == $bufsize). As is, you will shuffle every 514 lines. – ysth Nov 13 '08 at 18:12
-
I'm curious - Why do you think "real Perl hackers" would tear it apart? It's readable, it uses strict and warnings, and it gets the job done. – Sherm Pendley Nov 13 '08 at 18:44
-
Okay, my mistake. I thought you meant those who would turn it into one line of unreadable gibberish. *Real* Perl hackers understand the difference between production code and "Perl golf," and aside from fixing a few typos, wouldn't have a problem with your code. :-) – Sherm Pendley Nov 13 '08 at 22:41
-
@dehmann: I say so myself in the answer, which the OP accepted... I even state the reason for this non truly randomness. – Vinko Vrsalovic Jul 29 '10 at 23:35
6
This perl snippet does the trick :
#! /usr/bin/perl
# randomize cat
# fisher_yates_shuffle code copied from Perl Cookbook
# (By Tom Christiansen & Nathan Torkington; ISBN 1-56592-243-3)
use strict;
my @lines = <>;
fisher_yates_shuffle( \@lines ); # permutes @array in place
foreach my $line (@lines) {
print $line;
}
# fisher_yates_shuffle( \@array ) : generate a random permutation
# of @array in place
sub fisher_yates_shuffle {
my $array = shift;
my $i;
for ($i = @$array; --$i; ) {
my $j = int rand ($i+1);
next if $i == $j;
@$array[$i,$j] = @$array[$j,$i];
}
}
__END__

Steve Schnepp
- 4,620
- 5
- 39
- 54
5
use List::Util 'shuffle';
print shuffle <>
Or if you worry about last lines lacking \n,
chomp(my @lines = <>);
print "$_\n" for shuffle @lines;

ysth
- 96,171
- 6
- 121
- 214
-
This is the equivalent of TheSnide's solution using shuffle (eats everything up first, then shuffles) – Vinko Vrsalovic Nov 13 '08 at 19:02