哈希的自定义排序方法,它将自动使用适当的哈希值

时间:2015-06-01 14:36:34

标签: perl sorting hash

我的哈希包含二进制数字作为键:

# a class with my common element
class CommonLayout(forms.Form, Layout):
    code = forms.CharField(
        label='Serial Number',
        max_length=12,
        required=True,
    )

    def __init__(self, *args, **kwargs):
        super(CommonLayout, self).__init__(*args, **kwargs)

        self.helper = FormHelper(self)
        self.helper.form_method = 'POST'

        self.helper.layout = Layout (
            Field('code', css_class='form-control', placeholder='Read the Serial Number'),
        )

#the class with the form
class CollectionForms(forms.Form):

    def __init__(self, *args, **kwargs):
        super(CollectionForms, self).__init__(*args, **kwargs)

        self.helper = FormHelper(self)
        self.helper.form_action = 'collection'

        self.helper.layout.append(
            CommonLayout(),
            FormActions(
                StrictButton('Pass', type="submit", name="result", value="True", css_class="btn btn-success"),
            )
        )

在perl中我可以使用自定义函数来排序哈希。这是我将二进制数从最低到最大排序的功能:

my %h = ("1010" => 1, "1110" => 0, "0001" => 3, "1100" => 2);

我可以按照以下方式使用此函数对哈希进行排序:

sub sort_binary_numbers {
  my $a_dec = oct("0b".$a);
  my $b_dec = oct("0b".$b);
  return $a_dec <=> $b_dec;
}

结果将是:

print Dumper sort sort_binary_numbers keys %h;

我想使用值而非键来排序哈希。我可以这样做:

$VAR1 = '0001';
$VAR2 = '1010';
$VAR3 = '1100';
$VAR4 = '1110';

正如您所看到的,我必须在排序块中使用哈希名称。问题是如何重写此排序块以实现功能(如上例所示)并自动在函数中获取相应的哈希名称。我已尝试使用print Dumper sort { $h{$b} <=> $h{$a} } keys %h; 访问哈希名称,但未打印,例如。

@_

并按照以下方式调用:

sub sort_by_value {
  print Dumper @_; # This was not printed
  print ref @_;    # This was not printed
  return $b <=> $a;
}

有趣的是,当我将这个排序包装到另一个函数并从该函数循环调用它时,我将得到先前丢失的数据转储器的输出(但我仍然没有得到ref命令的输出) :

print Dumper sort sort_by_value keys %h;

然后我得到了这个输出:

sub calling_from_function {
  my %h = %{$_[0]};
  foreach my $key (sort sort_by_value keys %h){
  }
}

&calling_from_function(\%h);

问题:

  1. 如何用函数替换此命令$VAR1 = { '0001' => 3, '1010' => 1, '1110' => 0, '1100' => 2 }; $VAR1 = { '0001' => 3, '1010' => 1, '1110' => 0, '1100' => 2 }; $VAR1 = { '0001' => 3, '1010' => 1, '1110' => 0, '1100' => 2 }; $VAR1 = { '0001' => 3, '1010' => 1, '1110' => 0, '1100' => 2 }; 中的排序块,并在sortign函数中获取相应的哈希名称?
  2. 为什么包装其他功能有效?
  3. 为什么print Dumper sort { $h{$b} <=> $h{$a} } keys %h;不起作用?

3 个答案:

答案 0 :(得分:4)

排序子程序不会通过@_通过$a$b来正常获取参数(即除非涉及原型)。 ref @array永远不会返回任何内容,因为数组永远不会作为参考。

由另一个函数包装有效,因为您通过参数将@_填充到包装器中。

使用包装器对任何哈希进行排序:

sub sort_by_value {
    my %h = @_;
    return sort { $h{$b} <=> $h{$a} } keys %h
}

print Dumper(sort_by_value(%h));

您还可以将哈希引用发送到子例程:

sub sort_by_value {
    my ($h) = @_;
    return sort { $h->{$b} <=> $h->{$a} } keys %$h
}

print Dumper sort_by_value(\%h);

答案 1 :(得分:3)

所以你想拥有一个通用的排序功能,比如

my $sorter = sub { $_[0]{$b} <=> $_[0]{$a} };

当需要排序时,只需使用

即可
my @sorted_keys = sort { $sorter->(\%h) } keys(%h);

答案 2 :(得分:3)

你可以使用hash作为列表,将其转换为k / v aref对,对值进行排序(第二个元素),并从排序列表中选择键(大致是伪装的Schwartzian变换)。

use strict;
use warnings;
use List::Util 'pairs';

my %h = ("1010" => 1, "1110" => 0, "0001" => 3, "1100" => 2);
my @k = map $_->[0],
   sort { $b->[1] <=> $a->[1] }
   pairs %h;

没有额外的模块,

my @k = map $_->[0],
   sort { $b->[1] <=> $a->[1] }
   map [ $_, $h{$_} ],
   keys %h;