为什么这个 Perl 洗牌函数不洗牌?

Why does this Perl shuffle function not shuffle?

#!/usr/bin/perl

use Data::Dumper;
use strict;
use List::Util qw(shuffle);

my @arr = [qw(Foo Bar Baz Qux Quux Quuz)];
@arr = shuffle @arr;
print Dumper @arr;

Perl 版本为 v5.32.0。我看到的结果总是 Foo Bar Baz Qux Quux Quuz.

$ ~/tmp/shuffle.perl
$VAR1 = [
      'Foo',
      'Bar',
      'Baz',
      'Qux',
      'Quux',
      'Quuz'
    ];
$ /usr/bin/perl --version

This is perl 5, version 32, subversion 0 (v5.32.0) built for x86_64-linux-gnu-thread-multi

my @arr = [qw(Foo Bar Baz Qux Quux Quuz)];

这是一个只有一个元素的数组,即元素 [qw(Foo Bar Baz Qux Quux Quuz)]。因此这里没有什么可以洗牌的。您可能想要的是:

 my @arr = qw(Foo Bar Baz Qux Quux Quuz);

这是您现有的代码:

use Data::Dumper;
use strict;
use List::Util qw(shuffle);

my @arr = [qw(Foo Bar Baz Qux Quux Quuz)];
@arr = shuffle @arr;
print Dumper @arr;

您的数组如下所示:

@arr = (
    [qw(Foo Bar Baz Qux Quux Quuz)], # @arr element zero
                                     # @arr element 1 doesn't exist
                                     # @arr element 2 doesn't exist
                                     # etc...
);

换句话说,您的数组包含单个元素。该元素是对包含 Foo, Bar, Baz, Qux, Quux, Quuz 的匿名数组的引用。您创建了一个多级数据结构。

你有两条前进的道路。如果你真的想要一个多级数据结构,那么对$arr[0]引用的匿名数组中的元素进行排序可以这样洗牌:

@{$arr[0]} = shuffle(@{$arr[0]});

如果您不需要多级数据结构,您应该这样定义 @arr

@arr = qw(.........); # Notice the lack of [ and ]

然后洗牌变成:

@arr = shuffle(@arr);

[LIST]语法构成匿名数组引用构造函数。您可能不需要匿名数组引用。

https://perldoc.perl.org/perlreftut 是一个很好的 Perl 参考教程。

https://perldoc.perl.org/perldsc 是创建 Perl 数据结构的很好参考。

List::Util 的 shuffle 函数是 Perl XS 中的 Fisher Yates Shuffle 实现(本质上是用 C 实现的)。它被大量使用并且是核心 Perl 发行版的一部分,并且自 Perl 5.8 以来一直作为 Perl 的一部分发行,这可以追溯到十多年前。它非常坚固,可以正常工作。