【问题标题】:Array sorting in PerlPerl 中的数组排序
【发布时间】:2017-04-29 10:38:20
【问题描述】:

我是 Perl 新手,遇到了一个(可能很简单)数组排序问题。

我继承了一些 Perl 代码,这些代码将文本文件中的行读入三个一维数组 (x,y,z)。我希望能够使用其中一个维度作为键对这些数组进行排序,并重新排序其他两个维度以匹配。

例如,如果我的输入是:

  • @x = (1, 3, 2)
  • @y = (11,13,12)
  • @z = (21,23,22)

我按 x 排序,我希望结果是:

  • @x = (1, 2, 3)
  • @y = (11,12,13)​​
  • @z = (21,22,23)

如果这样可以让生活更轻松,我可以将三个一维数组合并为一个二维数组。

【问题讨论】:

  • 您的示例数据可能会被清除 - @y 和 @z 中的值与 @x 的顺序相同。具有非常不同的值(甚至像'a','b','c'之类的值)会使它们更清楚地准确排序

标签: perl


【解决方案1】:

没有必要将所有数组合并在一起。使用sort@x 中的元素获取正确的索引排序:

@sort_by_x = sort { $x[$a] <=> $x[$b] } 0 .. $#x;    #   ==> (0, 2, 1)

然后将该索引排序应用于任何其他数组:

@x = @x[@sort_by_x];
@y = @y[@sort_by_x];
@z = @z[@sort_by_x];

【讨论】:

    【解决方案2】:
    use strict;
    use warnings;
    use Data::Dumper;
    
    use List::Util qw(reduce);
    
    my @x = (1, 3, 2);
    my @y = (11, 13, 12);
    my @z = (21, 23, 22);
    
    my @combined = map { [ $x[$_], $y[$_], $z[$_] ] } 0 .. $#x;
    my @sorted = sort { $a->[0] <=> $b->[0] } @combined;
    my $split_ref = reduce { push @{$a->[$_]}, $b->[$_] for 0 .. $#$a; $a;} [[], [], []], @sorted;
    
    print Dumper \@combined;
    print Dumper \@sorted;
    print Dumper $split_ref;
    

    这基本上会给你:

        [
          [
            1,
            2,
            3
          ],
          [
            11,
            12,
            13
          ],
          [
            21,
            22,
            23
          ]
        ];
    

    【讨论】:

      【解决方案3】:

      合并确实可以让生活更轻松。

      @sorted = sort { $a->[0] <=> $b->[0] } 
          ( [$x[0], $y[0], $z[0]], [$x[1], $y[1], $z[1]], [$x[2], $y[2], $z[2]] );
      

      可能会这样做。你当然不想手写所有这些!

      【讨论】:

        【解决方案4】:

        如果@x 与@y 和@z 大小相同,则无需排序 - 您可以使用数组切片代替!

        use strict;
        use warnings;
        use 5.010;
        
        my @x = (1, 3, 2);
        my @y = (11,13,12);
        my @z = (21,23,22);
        
        say join ', ', @y;
        @y = @y[ map { $_ - 1 } @x ]; #We use map create a lists of the values of elements in @x, minus 1.
        say join ', ', @y;
        

        当然,如果你只是想按数字顺序排序,那么使用@x 是多余的:

        @y = sort { $a <=> $b } @y;
        

        最后,如果你想对任意数量的数组进行排序,你可以创建一个数组数组,或者将一个引用列表传递给一个 for,ala

        my @indexes = map { $_ - 1 } @x;
        
        for my $array_ref ( \@x, \@y, \@z ) {
            @$array_ref = @{$array_ref}[@indexes];
        }
        

        【讨论】:

        • 我认为您不能安全地假设@x 中的值可以用作索引。如果它们是负数或不是唯一的怎么办?
        • 负数或重复不会真的很麻烦(毕竟这是他的规范......),但数组之外的索引会触发警告。但是,是的,警告程序员。
        • 它们很麻烦,因为它们会给你不正确的结果而不发出警告。尝试将未排序的 @x 更改为 (1,3,3)。
        • 再次,他的规范 - 来自 OP:“我按 x 排序”我认为这意味着他不是简单地对数组进行数字排序。
        【解决方案5】:

        试一试:

        #!/usr/bin/perl 
        use 5.10.1;
        use strict;
        use warnings;
        use Data::Dumper;
        
        my @x = (1, 3, 2);
        my @y = (11,13,12);
        my @z = (21,23,22);
        
        my (%y, %z);
        
        @y{@x} = @y;
        @z{@x} = @z;
        
        my @xs = sort @x;
        my @ys = @y{@xs};
        my @zs = @z{@xs};
        say Dumper \@xs,\@ys,\@zs;
        

        输出:

        $VAR1 = [
                  1,
                  2,
                  3
                ];
        $VAR2 = [
                  11,
                  12,
                  13
                ];
        $VAR3 = [
                  21,
                  22,
                  23
                ];
        

        【讨论】:

        • 如果@x 有任何重复值,则会中断。
        【解决方案6】:

        @a = sort { $a <=> $b } @a;
        

        另见sort on perldoc

        【讨论】:

        • 不会对@y@z 进行排序。
        • 是的,这将对一维数组之一进行排序。它不会对其他两个进行排序以匹配。我希望能够按 x 数组排序并重新排序 y 和 z 数组以匹配,以便保留文本文件中的行。如果我的问题不清楚,我很抱歉。 --amb
        猜你喜欢
        • 2015-05-18
        • 1970-01-01
        • 2018-01-14
        • 2011-07-14
        • 2019-04-10
        • 2011-02-25
        • 2011-12-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多