【发布时间】:2021-03-07 15:11:21
【问题描述】:
我有一个表格文件,我想在 Perl 中打乱特定列的行。
例如,我有这个数组:
a 1
b 2
c 3
d 4
e 5
f 6
我想洗牌第二列得到这样的东西:
a 2
b 1
c 3
d 4
e 5
f 6
【问题讨论】:
我有一个表格文件,我想在 Perl 中打乱特定列的行。
例如,我有这个数组:
a 1
b 2
c 3
d 4
e 5
f 6
我想洗牌第二列得到这样的东西:
a 2
b 1
c 3
d 4
e 5
f 6
【问题讨论】:
我可以使用这个脚本来完成这项工作:
#!/usr/bin/env perl
use strict;
use warnings;
use List::Util qw/shuffle/;
my @c = split /,/, $ARGV[0];
$_-- for @c;
shift;
my @lines;
my @v;
while ( <> ) {
my @items = split;
$v[$.-1] = [@items[@c]];
$lines[$.-1] = [@items];
}
my @order = shuffle (0..$#lines);
for my $l (0..$#lines) {
my @items = @{ $lines[$l] };
@items[@c] = @{ $lines[$order[$l]] }[@c];
print "@items\n";
}
此脚本使用List::Util,它是自 perl v5.7.3 以来 Perl 核心模块的一部分:corelist List::Util
可以用perl shuffle.pl 2 test.txt启动
【讨论】:
$[ (perldoc.perl.org/perlvar#$%5B) 的文档,我发现它开始不再有效从 Perl v5.30.0 开始,即使没有做 use v5.16,所以我不得不从我的脚本中删除 $[=1 的使用 :(.
不允许使用外部模块时的示例代码。
use strict;
use warnings;
use feature 'say';
my %data;
while( <DATA> ) {
my($l,$d) = split;
$data{$l} = $d;
}
say '- Loaded --------------------';
say "$_ => $data{$_}" for sort keys %data;
for( 0..5 ) {
@data{ keys %data} = @{ shuffle([values %data]) };
say "-- $_ " . '-' x 24;
say "$_ => $data{$_}" for sort keys %data;
}
sub shuffle {
my $data = shift;
my($seen, $r, $i);
my $n = $#$data;
for ( 0..$n ) {
do {
$i = int(rand($n+1));
} while defined $seen->{$i};
$seen->{$i} = 1;
$r->[$_] = $data->[$i];
}
return $r;
}
__DATA__
a 1
b 2
c 3
d 4
e 5
f 6
输出
- Loaded --------------------
a => 1
b => 2
c => 3
d => 4
e => 5
f => 6
-- 0 ------------------------
a => 5
b => 4
c => 2
d => 6
e => 1
f => 3
-- 1 ------------------------
a => 3
b => 6
c => 2
d => 4
e => 1
f => 5
-- 2 ------------------------
a => 4
b => 5
c => 6
d => 1
e => 3
f => 2
-- 3 ------------------------
a => 6
b => 4
c => 1
d => 2
e => 3
f => 5
-- 4 ------------------------
a => 3
b => 4
c => 6
d => 5
e => 1
f => 2
-- 5 ------------------------
a => 6
b => 5
c => 3
d => 4
e => 2
f => 1
【讨论】:
使用List::Util::shuffle 可能是个好主意。我使用Schwartzian transform 创建了一个随机数列表,对它们进行排序,然后根据数组索引插入列数据。
use strict;
use warnings;
use feature 'say';
my @col;
while (<DATA>) {
push @col, [ split ];
}
my @shuffled = map { $col[$_->[0]][1] } # map to @col values
sort { $a->[1] <=> $b->[1] } # sort based on rand() value
map { [ $_, rand() ] } # each index mapped into array of index and rand()
0 .. $#col; # list of indexes of @col
for my $index (0 .. $#col) {
say join " ", $col[$index][0], $shuffled[$index];
}
__DATA__
a 1
b 2
c 3
d 4
e 5
f 6
【讨论】: