How can I print the lines in STDIN in random order

2019-01-24 20:29发布

I want to do the inverse of sort(1) : randomize every line of stdin to stdout in Perl.

3条回答
疯言疯语
2楼-- · 2019-01-24 21:12

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__
查看更多
SAY GOODBYE
3楼-- · 2019-01-24 21:13
use List::Util 'shuffle';
print shuffle <>

Or if you worry about last lines lacking \n,

chomp(my @lines = <>);
print "$_\n" for shuffle @lines;
查看更多
迷人小祖宗
4楼-- · 2019-01-24 21:23

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.
查看更多
登录 后发表回答