首先抱歉我的英语 - 我希望你能理解我。
有一个哈希:
$hash{a} = 1;
$hash{b} = 3;
$hash{c} = 3;
$hash{d} = 2;
$hash{e} = 1;
$hash{f} = 1;
我想按值(而不是键)对它进行排序,所以我有:
for my $key ( sort { $hash{ $a } <=> $hash{ $b } } keys %hash ) { ... }
首先,我得到值为1的所有键,然后是值2,等等......很棒。
但是如果哈希没有改变,那么键的顺序(按此值排序)总是相同的。
问题:我如何改变排序结果,所以每次运行'for'循环时,我得到不同的键顺序,值为1,值为2等?
答案 0 :(得分:4)
我不太清楚我是否理解你的需求,但这是好的:
use List::Util qw(shuffle);
my %hash;
$hash{a} = 1;
$hash{b} = 3;
$hash{c} = 3;
$hash{d} = 2;
$hash{e} = 1;
$hash{f} = 1;
for my $key (sort { $hash{ $a } <=> $hash{ $b } } shuffle( keys %hash )) {
say "hash{$key} = $hash{$key}"
}
答案 1 :(得分:3)
您可以简单地添加另一级别的排序,当常规排序方法无法区分两个值时,将使用这种排序。 E.g:
sort { METHOD_1 || METHOD_2 || ... METHOD_N } LIST
例如:
sub regular_sort {
my $hash = shift;
for (sort { $hash->{$a} <=> $hash->{$b} } keys %$hash) {
print "$_ ";
};
}
sub random_sort {
my $hash = shift;
my %rand = map { $_ => rand } keys %hash;
for (sort { $hash->{$a} <=> $hash->{$b} ||
$rand{$a} <=> $rand{$b} } keys %$hash ) {
print "$_ ";
};
}
答案 2 :(得分:2)
要按值对键进行排序,使用具有相同值的键的随机排序,我会看到两个解决方案:
use List::Util qw( shuffle );
use sort 'stable';
my @keys =
sort { $hash{$a} <=> $hash{$b} }
shuffle keys %hash;
或
my @keys =
map $_->[0],
sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] }
map [ $_, $hash{$_}, rand ],
keys %hash;
要求use sort 'stable';
阻止sort
破坏shuffle
返回的列表的随机性。
以上对Schwartzian Transform的使用不是优化尝试。我看到人们在比较函数本身中使用rand
来尝试实现上述结果,但这样做有两个原因。
当使用诸如此类的“行为不当”比较时,结果被记录为 undefined ,因此允许sort
返回垃圾,重复元素,缺少元素等。
即使sort
没有返回垃圾,也不会是合理的。结果将被称重。
答案 3 :(得分:1)
您可以使用升序和降序两个函数,并相应地使用它们,如
sub hasAscending {
$hash{$a} <=> $hash{$b};
}
sub hashDescending {
$hash{$b} <=> $hash{$a};
}
foreach $key (sort hashAscending (keys(%hash))) {
print "\t$hash{$key} \t\t $key\n";
}
foreach $key (sort hashDescending (keys(%hash))) {
print "\t$hash{$key} \t\t $key\n";
}
答案 4 :(得分:1)
好像你想随机化循环键。
Perl,不按顺序或排序顺序存储,但这对你来说似乎不够随意,所以你可能想要创建一个键数组并循环遍历它。
首先,使用键填充数组,然后使用随机数算法(1 .. $ #length_of_array)将数组中该位置的键推送到array_of_keys。
如果你试图随机化按值排序哈希的键,那就有点不同了。
my %hash = (a=>1, b=>3, c=>3, d=>2, e=>1, f=>1);
my %hash_by_val;
for my $key ( sort { $hash{$a} <=> $hash{$b} } keys %hash ) {
push @{ $hash_by_val{$hash{$key}} }, $key;
}
for my $key (sort keys %hash_by_val){
my @arr = @{$hash_by_val{$key}};
my $arr_ubound = $#arr;
for (0..$arr_ubound){
my $randnum = int(rand($arr_ubound));
my $val = splice(@arr,$randnum,1);
$arr_ubound--;
print "$key : $val\n"; # notice: output varies b/t runs
}
}