【问题标题】:Sorting an array of hashes which have alphanumeric values对具有字母数字值的哈希数组进行排序
【发布时间】:2014-08-03 15:37:57
【问题描述】:

我遇到了对哈希数组进行排序的问题;具有我需要排序的字母数字值的哈希。

参考这个question!我的问题是这个问题的延伸。 我尝试了上述问题中的解决方案,但没有得到所需的输出。

$arr_ref = [
  { brand => "A.1", PO => "1.a", supplier => "X" },
  { brand => "A.2", PO => "2.a", supplier => "X" },
  { brand => "B.1", PO => "1.b", supplier => "X" },
  { brand => "B.2", PO => "2.b", supplier => "X" },
  { brand => "B.3", PO => "1.c", supplier => "Y" },
]

我需要按品牌或采购订单排序。

#sort the array reference and place the array back into the standard_set
$arr_ref = [sort by_brand @$arr_ref];
sub by_brand {
    $a->{brand} cmp $b->{brand}
}

复杂性是关键;可以以数字或字母字符开头。 品牌或采购订单也可以有不同的大小。分隔符可以是点或连字符。

我们能否根据$arr_ref 中收到的输入来解决这个问题?

【问题讨论】:

    标签: arrays regex perl sorting perl-data-structures


    【解决方案1】:

    你真的很亲密。您只需要删除[ 和] 括号并取消引用您要分配给@$array_ref = ... 的数组。

    use strict;
    use warnings;
    
    my $arr_ref = [
      { brand => "B.3", PO => "1.c", supplier => "Y" },
      { brand => "B.2", PO => "2.b", supplier => "X" },
      { brand => "B.1", PO => "1.b", supplier => "X" },
      { brand => "A.2", PO => "2.a", supplier => "X" },
      { brand => "A.1", PO => "1.a", supplier => "X" },
    ];
    
    my @sorted = sort { $a->{brand} cmp $b->{brand} } @$arr_ref;
    
    use Data::Dump;
    dd @sorted;
    

    输出:

    (
      { brand => "A.1", PO => "1.a", supplier => "X" },
      { brand => "A.2", PO => "2.a", supplier => "X" },
      { brand => "B.1", PO => "1.b", supplier => "X" },
      { brand => "B.2", PO => "2.b", supplier => "X" },
      { brand => "B.3", PO => "1.c", supplier => "Y" },
    )
    

    【讨论】:

      【解决方案2】:

      使用Schwartzian transform 对其进行排序,并为每个字段正确比较器。

      use strict;
      use warnings;
      use Data::Dumper;
      my $arr_ref = [
          { brand => "A.1", PO => "1.a", supplier => "X" },
          { brand => "A.2", PO => "2.a", supplier => "X" },
          { brand => "B.1", PO => "1.b", supplier => "X" },
          { brand => "B.2", PO => "2.b", supplier => "X" },
          { brand => "B.3", PO => "1.c", supplier => "Y" },
      ];
      my @sorted = map $_->[0], sort {
                 $a->[1][0] cmp $b->[1][0]
              or $a->[1][1] <=> $b->[1][1]
              or $a->[1][2] <=> $b->[1][2]
              or $a->[1][3] cmp $b->[1][3]
          } map [ $_, [ map split( /[.-]/, $_, 2 ), @$_{qw(brand PO)} ] ],
          @$arr_ref;
      print Dumper( \@sorted );
      

      尝试使用品牌"A.10" 来发现差异。

      【讨论】:

      • [ map split(/[.-]/, $_, 2), @$_{qw(brand PO)} ] 如果你喜欢 DRY。
      【解决方案3】:

      试试这种排序方法:

      sub by_brand_or_po {
          my ($a_ba, $a_bn) = split /\.|-/, $a->{brand};
          my ($b_ba, $b_bn) = split /\.|-/, $b->{brand};
      
          my ($a_pa, $a_pn) = split /\.|-/, $a->{PO};
          my ($b_pa, $b_pn) = split /\.|-/, $b->{PO};
      
          return( $a_ba cmp $b_ba or $a_bn <=> $b_bn or
                  $a_pa cmp $b_pa or $a_pn <=> $b_pn );
      }
      

      它将品牌字母优先于数字而不是 PO 字母优先于 PO 数字,并且将分割为点或连字符。

      【讨论】:

        【解决方案4】:

        使用Sort::Key::Natural!

        use Sort::Key::Natural qw(natkeysort);
        
        my @sorted_by_brand = natkeysort { $_->{brand} } @data;
        my @sorted_by_po = natkeysort { $_->{po} } @data;
        

        【讨论】:

          猜你喜欢
          • 2014-04-13
          • 1970-01-01
          • 2016-04-27
          • 2022-01-04
          • 2011-12-26
          • 1970-01-01
          • 2020-04-05
          • 2015-04-08
          • 2019-04-25
          相关资源
          最近更新 更多