【问题标题】:How can I do alpha numeric sort in Perl?如何在 Perl 中进行字母数字排序?
【发布时间】:2012-06-19 13:54:32
【问题描述】:

我有一个如下所示的文件:

80,1p21
81,19q13
82,6p12.3
83,Xp11.22
84,3pter-q21
86,3q26.33
87,14q24.1-q24.2|14q24|14q22-q24
88,1q42-q43
89,11q13.1
90,2q23-q24
91,12q13
92,2q22.3
93,3p22
94,12q11-q14
95,3p21.1
97,14q24.3
98,2p16.2

我想根据第二列对它们进行排序。第一列也应该相应改变。当您在 Perl 中使用“排序”命令时,它不会这样做,因为它说它不是数字。有没有办法在 Perl 中对事物进行 alpha 数字排序?

【问题讨论】:

  • 另外,如果您已经将它们放在一个文件中,您可以尝试使用 unix 排序命令。对文件进行排序的 perl 脚本太过分了。
  • 为什么 RTFM 获得了四票。如果您不想回答初学者的问题,那就不要回答它们。指出文档并没有错,但要为链接提供一些价值,就像 Dave Cross 在下面所做的那样。
  • 这个问题在这里被问了很多次。文档很好地涵盖了它。现在让我问你:你不是说忽略搜索对初学者来说是正确的事情吗?在我看来,事实恰恰相反:对于初学者来说,尽快开始使用搜索更为重要。
  • @lanZZ:perl 的排序文档没有多大帮助。如果我使用词法排序,它会将 1p21 19q13 6p12.3 11q13.1 2q23-q24 排序为 11q13.1 19q13 1p21 2q23-q24 6p12.3。这不是我需要的。
  • @Ianzz:所以你是执行“提出重要问题或 RTFM”政策的 SO 警察?使用 SO 来教授更多内容,而不是“沉浸在 5000 页的 perl 文档中”。教,“这是在 5000 页的文档中找到它的方法”,“在为您的问题选择正确答案时要考虑的其他相关事项”。教他们钓鱼技巧,不要只是告诉他们去钓鱼。

标签: perl sorting alphanumeric


【解决方案1】:

如果您阅读the documentation for sort,您会发现您不需要在 Perl 中进行数字排序。您也可以进行字符串比较。

@sorted = sort { $a cmp $b } @unsorted;

但这仍然会给您带来问题,例如,19q 会在 6p 之前排序。因此,您可以编写自己的排序函数,该函数可以在进行比较之前进行任何您想要的转换。

@sorted = sort my_complex_sort @unsorted;

sub my_complex_sort {
  # code that compares $a and $b and returns -1, 0 or 1 as appropriate
  # It's probably best in most cases to do the actual comparison using cmp or <=>

  # Extract the digits following the first comma
  my ($number_a) = $a =~ /,(\d+)/;
  my ($number_b) = $b =~ /,(\d+)/;

  # Extract the letter following those digits
  my ($letter_a) = $a =~ /,\d+(a-z)/;
  my ($letter_b) = $b =~ /,\d+(a-z)/;

  # Compare and return
  return $number_a <=> $number_b or $letter_a cmp $letter_b;
}

【讨论】:

  • 使用排序::版本;另一种方法。 @allFileArraySorted = 排序 { versioncmp($a,$b) } @allFileArray;
【解决方案2】:
#!/usr/bin/env perl

use strict;
use warnings;

my @datas   = map { /^(\d+),(\d*)(.*)$/; [$1, $2, $3]; } <DATA>;
my @res     = sort {$a->[1] <=> $b->[1] or $a->[2] cmp $b->[2]} @datas;
foreach my $data (@res) {
    my ($x, $y, $z) = @{$data};
    print "$x,$y$z\n";
}

__DATA__
80,1p21
81,19q13
82,6p12.3
83,Xp11.22
84,3pter-q21
86,3q26.33
87,14q24.1-q24.2|14q24|14q22-q24
88,1q42-q43
89,11q13.1
90,2q23-q24
91,12q13
92,2q22.3
93,3p22
94,12q11-q14
95,3p21.1
97,14q24.3
98,2p16.2 

【讨论】:

  • 例如,这将在 6p12.3 之前对 19q13 进行排序。我认为这不是 OP 想要的。
【解决方案3】:

我实际上找到了答案。代码看起来有点复杂。

#!/usr/bin/env perl

use strict;  
use warnings;

sub main {   
my $file;  
if (@ARGV != 1) {   
    die "Usage: perl hashofhash_sort.pl <filename>\n";
}   
else {  
    $file = $ARGV[0];   
}  

open(IN, $file) or die "Error!! Cannot open the $file file: $!\n";
my @file = <IN>;
chomp @file;
my ($entrez_gene, $loci, $chr, $band, $pq, $band_num);
my (%chromosome, %loci_entrez);

foreach my $line (@file) {
    if ($line =~ /(\d+),(.+)/) {
        # Entrez genes
        $entrez_gene = $1;

        # Locus like 12p23.4
        $loci = $2;

        if ($loci =~ /^(\d+)(.+)?/) {
            # chromosome number alone (only numericals)
            $chr = $1;
            if ($2) {
                # locus minus chromosome number. If 12p23.4, then $band is p23.4
                $band = "$2";
                if ($band =~ /^([pq])(.+)/) {
                    # either p or q
                    $pq = $1;
                    # stores the numericals. for p23.4, stores 23.4
                    $band_num = $2;
                }

                if (exists $chromosome{$chr}) {
                    if (exists $chromosome{$chr}{$pq}) {
                        push (@{$chromosome{$chr}{$pq}}, $band_num);
                    }
                    else {
                        $chromosome{$chr}{$pq} = [$band_num];
                    }
                }

                else {
                    $chromosome{$chr}{$pq} = [$band_num];
                }
            }
        }
    }
} # End of foreach loop

foreach my $key (sort {$a <=> $b} keys %chromosome) {
    my %seen = ();
    foreach my $key2 (sort {$a cmp $b } keys %{$chromosome{$key}}) {
        my @unique = grep { ! $seen{$_}++ } @{$chromosome{$key}{$key2}};
        my @sorted = sort @unique;
        foreach my $element (@sorted) {
            my $sorted_locus = "$key$key2$element";
            if (exists $loci_entrez{$sorted_locus}) {
                foreach my $element2 (@{$loci_entrez{$sorted_locus}}) {
                        print "$element2,$sorted_locus\n";

                }
            }
        }
    }

}


} # End of main

main();

【讨论】:

  • 解释一下。例如,想法是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 2011-04-04
  • 2011-02-06
  • 1970-01-01
  • 2016-05-19
  • 2023-03-06
  • 2011-07-25
相关资源
最近更新 更多