更好的方法来排序具有不寻常值的数组

时间:2012-02-28 16:27:47

标签: arrays perl

我有这个数组:

@raw_stack = (
    '900244~dfasdf~ddd3',
    '900122~dfasdf~ddd1',
    '900244~dfasdf~ddd2',
    '900456~dfasdf~ddd4',
    '900312~dfasdf~ddd3',
    '900456~dfasdf~ddd5',
    );

我想用第一个'〜'元素对它进行排序。 是否有一种更优雅的方式来解决这个而不是 循环和拆分每个值?

4 个答案:

答案 0 :(得分:5)

使用Schwartzian transform

my @raw_stack = (
    '900244~dfasdf~ddd3',
    '900122~dfasdf~ddd1',
    '900244~dfasdf~ddd2',
    '900456~dfasdf~ddd4',
    '900312~dfasdf~ddd3',
    '900456~dfasdf~ddd5',
);
my @sorted = 
    map { $_->[0] }
    sort { $a->[1] <=> $b->[1] }
    map { [$_, (split/~/)[0]] } @raw_stack;
dump@sorted;

<强>基准:

#!/usr/bin/perl 
use 5.010;
use strict;
use warnings;
use Benchmark qw(:all);


my $s = '~dfasdf~ddd3';
my @arr = ();
for(0..20000) {
    push @arr, int(rand(100000)) . $s;
}
my $count = -3;
cmpthese($count, {
        'ST' => sub {
            my @sorted = 
                map { $_->[0] }
                sort { $a->[1] <=> $b->[1] }
                map { [$_, (split/~/)[0]] } @arr;
        },
        'SORT' => sub {
            my @sorted =
                sort {
                    my ($a_0) = split /~/, $a;
                    my ($b_0) = split /~/, $b;
                    $a_0 <=> $b_0
                } @arr;
        },
    });

<强>结果:

包含200个元素的数组:

      Rate SORT   ST
SORT 267/s   -- -61%
ST   689/s 158%   --

2000个元素的数组:

       Rate SORT   ST
SORT 18.0/s   -- -71%
ST   61.5/s 242%   --

20000个元素的数组:

       Rate SORT   ST
SORT 1.35/s   -- -73%
ST   4.96/s 266%   --

答案 1 :(得分:4)

排序并列出切片?

sort { ( split( /~/, $a ) )[0] <=> ( split( /~/, $b ) )[0] } @raw_stack;

答案 2 :(得分:2)

这些可能有所帮助。它们向您展示了如何提取字符串的一部分以使用它们来对较大的字符串进行排序:

答案 3 :(得分:1)

总是6位数吗?如果是这样,以下将是最简单和最快的:

my @sorted_stack = sort @raw_stack;

如果没有,

my @sorted_stack =
   sort {
      my ($a_0) = split /~/, $a;
      my ($b_0) = split /~/, $b;
      $a_0 <=> $b_0
   } @raw_stack;

如果你已经习惯了Schwartzian变换可能会更清晰,但在这种情况下它实际上更慢:[更新:显然,它实际上比我对大型列表的第二个解决方案更快。它永远不会比第一个更快,但是

my @sorted_stack =
   map $_->[0],
    sort { $a->[1] <=> $b->[1] }
     map [ $_, split /~/ ],
      @raw_stack;