我从一个人那里继承了一些代码,他们最喜欢的时间是将每一行缩短到绝对最小值(有时只是为了让它看起来很酷).他的代码很难理解,但我设法理解(并重写)其中的大部分内容.
现在我偶然发现了一段代码,无论我怎么努力,我都无法理解.
my @heads = grep {s/\.txt$//} OSA::Fast::IO::Ls->ls($SysKey,'fo','osr/tiparlo',qr{^\d+\.txt$}) || ();
my @selected_heads = ();
for my $i (0..1) {
$selected_heads[$i] = int rand scalar @heads;
for my $j (0..@heads-1) {
last if (!grep $j eq $_, @selected_heads[0..$i-1]);
$selected_heads[$i] = ($selected_heads[$i] + 1) % @heads; #WTF?
}
my $head_nr = sprintf "%04d", $i;
OSA::Fast::IO::Cp->cp($SysKey,'',"osr/tiparlo/$heads[$selected_heads[$i]].txt","$recdir/heads/$head_nr.txt");
OSA::Fast::IO::Cp->cp($SysKey,'',"osr/tiparlo/$heads[$selected_heads[$i]].cache","$recdir/heads/$head_nr.cache");
}
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这应该是某种随机函数,但我从未见过更复杂的方法来实现随机性.或者我的假设是错误的?至少,这就是这段代码应该做的事情.选择2个随机文件并复制它们.
===注意===
OSA框架是我们自己的框架.它们以UNIX对应方式命名,并进行一些基本测试,以便应用程序不需要为此烦恼.
bri*_*foy 12
这看起来像一些带有Perl语法的C代码.有时候知道这个人正在思考的语言可以帮助你弄清楚发生了什么.在这种情况下,人的大脑感染了内存管理,指针算术和其他低级别问题的内部工作,所以他想要精确控制一切:
my @selected_heads = ();
# a tricky way to make a two element array
for my $i (0..1) {
# choose a random file
$selected_heads[$i] = int rand @heads;
# for all the files (could use $#heads instead)
for my $j (0..@heads-1) {
# stop if the chosen file is not already in @selected_heads
# it's that damned ! in front of the grep that's mind-warping
last if (!grep $j eq $_, @selected_heads[0..$i-1]);
# if we are this far, the two files we selected are the same
# choose a different file if we're this far
$selected_heads[$i] = ($selected_heads[$i] + 1) % @heads; #WTF?
}
...
}
Run Code Online (Sandbox Code Playgroud)
这是很多工作,因为原始程序员要么不理解哈希,要么不喜欢它们.
my %selected_heads;
until( keys %selected_heads == 2 )
{
my $try = int rand @heads;
redo if exists $selected_heads{$try};
$selected_heads{$try}++;
}
my @selected_heads = keys %selected_heads;
Run Code Online (Sandbox Code Playgroud)
如果您仍然讨厌哈希值并使用Perl 5.10或更高版本,则可以使用智能匹配来检查值是否在数组中:
my @selected_heads;
until( @selected_heads == 2 )
{
my $try = int rand @heads;
redo if $try ~~ @selected_heads;
push @selected_heads, $try;
}
Run Code Online (Sandbox Code Playgroud)
但是,您对此问题有特殊约束.由于您知道只有两个元素,因此您只需检查要添加的元素是否为先前元素.在第一种情况下它不会是undef,所以第一次添加总是有效.在第二种情况下,它不能是数组中的最后一个元素:
my @selected_heads;
until( @selected_heads == 2 )
{
my $try = int rand @heads;
redo if $try eq $selected_heads[-1];
push @selected_heads, $try;
}
Run Code Online (Sandbox Code Playgroud)
呵呵.我不记得我最后一次使用的until
时候它确实适合了这个问题.:)
请注意,如果原始文件的数量小于2,所有这些解决方案都会遇到无限循环的问题.我会添加一个更高的保护条件,以便通过错误添加no和single文件,也许两个文件案例不打算订购它们.
你可以这样做的另一种方法是将原始文件的整个列表改组(例如,使用List :: Util),然后取下前两个文件:
use List::Util qw(shuffle);
my @input = 'a' .. 'z';
my @two = ( shuffle( @input ) )[0,1];
print "selected: @two\n";
Run Code Online (Sandbox Code Playgroud)