如何反转阵列?

时间:2011-01-15 01:32:28

标签: perl

在此脚本中

#!/usr/bin/perl -w

use strict;

my @ar = (1,2,10,3,5);

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

@ar现在包含(1,2,3,5,10)

现在我想获得逆数组(4,6,7,8,9)

有什么建议可以做到吗?

7 个答案:

答案 0 :(得分:8)

使用set操作时,哈希工作正常:

my %have = map {$_ => 1} @ar;

my @inv  = grep {not $have{$_}} 1 .. 10;

print "@inv\n"; # 4 6 7 8 9

如果您事先不知道边界,并希望从@ar的最小值/最大值确定它们,因为它的排序变得容易:

my @inv = grep {not $have{$_}} $ar[0] .. $ar[-1];

答案 1 :(得分:6)

这是智能匹配的一个很好的应用程序:

  @inverse = grep { ! ($_ ~~ @ar) } 1..10;

选择1到10之间不在@ar中的所有值。

答案 2 :(得分:4)

Acme::Tools

use warnings;
use strict;
use Acme::Tools qw(minus);

my @ar = (1,2,10,3,5);
@ar = sort {$a <=> $b} @ar; 
my @all = 1..10;
my @inv = minus( \@all, \@ar );
print "@ar\n";
print "@inv\n";

答案 3 :(得分:3)

由于您知道数组已排序,因此在任何给定时间只需要比较1个值,因此您可以这样做:

my @ar = (1,2,10,3,5);

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

my @inverse = do {
  my $i = 0;
  grep { $_ != $ar[$i] or (++$i, 0) } 1 .. $ar[-1]
};

如此处所写,您不需要检查数组末尾的$i,因为范围在$ar[-1]结束。如果你改变了这个条件,那么你需要检查$i > $#ar,或者在计算逆转之前将N + 1推到@ar并在之后将其弹出(其中N是范围的最大值) )。此代码还假定数组中没有任何重复值。

我决定使用5,000到10,000之间的5000个数字对主要候选人进行基准测试:

use 5.010;
use Benchmark 'cmpthese';

my (@orig, %used);
while (@orig < 5000) {
  my $rand = 1 + int rand 10000;
  push @orig, $rand unless $used{$rand}++;
}

my @ar = sort {$a <=> $b} @orig;

cmpthese(-3, {
  sorted => sub {
    push @ar, 10001;
    my @inverse = do {
      my $i = 0;
      grep { $_ != $ar[$i] or (++$i, 0) } 1 .. 10000
    };
    pop @ar;
  },

  unsorted => sub {
    @ar = sort {$a <=> $b} @orig;

    push @ar, 10001;
    my @inverse = do {
      my $i = 0;
      grep { $_ != $ar[$i] or (++$i, 0) } 1 .. 10000
    };
    pop @ar;
  },

  hash => sub {
    my %have = map {$_ => 1} @ar;

    my @inverse = grep {not $have{$_}} 1 .. 10000;
  },

  smartmatch => sub {
    my @inverse = grep { ! ($_ ~~ @ar) } 1 .. 10000;
  },
});

在Perl 5.10.1上,我得到了:

              Rate smartmatch       hash   unsorted     sorted
smartmatch 0.708/s         --      -100%      -100%      -100%
hash         180/s     25279%         --        -7%       -67%
unsorted     193/s     27183%         8%         --       -65%
sorted       551/s     77745%       207%       185%         --

如您所见,对阵列的反复智能匹配是。如果您包括排序@ar所需的时间,我的方法与基于哈希的方法的速度大致相同。如果你打折(也许你出于其他原因必须排序@ar),那么我的方法大约是哈希的两倍。

答案 4 :(得分:0)

我的Perl有点生疏,但这是基本的想法。

# Put the contents of `@ar` into the keys 
# of a temporary hash variable (to make lookups easy)
my %temp_hash = %{{ map { $_ => 1 } @ar }};

# Then use a `for` loop starting at the first value
# in `@ar` and ending at the last value:
for (my $i = $ar[0]; $i <= $ar[$#ar-1]; $i++) {
    # For each value of your loop counter,
    # check whether that value exists as a key 
    # in your temporary hash variable. 
    # If it doesn't, push it on to your inverse array:
    push @inverse_array, $i if (not exists $temp_hash{$i});
}

完成工作!

答案 5 :(得分:0)

这是使用Set :: IntSpan的解决方案。

#!/usr/bin/perl
use strict;
use warnings;
use Set::IntSpan;

my @ar = (1,2,10,3,5); 
@ar = sort {$a <=> $b} @ar;

# min - max of given set
my $range = Set::IntSpan->new( "$ar[0]-$ar[-1]" );
# members of set
my $used  = Set::IntSpan->new( @ar );

# Calculates the missing numbers
my $unused = $range->diff( $used );

print join " ", $unused->elements;

答案 6 :(得分:-1)

简单

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

如果要反转随机非排序数组:

my @inv;
while(scalar @ar){
    push @inv pop @ar;
}