按perl中的第二个单词排序

时间:2011-03-05 01:40:27

标签: perl sorting

嘿伙计们, 我有这个名为phonebook的文件

Steve Blenheim:239-923-7366:238-934-7865:95 Latham Lane, Easton, PA 83755:11/12/56:20300
Betty Boop:245-836-8357:245-876-7656:635 Cutesy Lane, Hollywood, CA 91464:6/23/23:14500
Igor Chevsky:385-375-8395:385-333-8976:3567 Populus Place, Caldwell, NJ 23875:6/18/68:23400
Norma Corder:397-857-2735:397-857-7651:74 Pine Street, Dearborn, MI 23874:3/28/45:245700

我正在尝试从第二个单词(姓氏)按反向字母顺序对文本进行排序,但却无法找到如何执行此操作。我这样做是从文件中读取的

  open (FILE, phonebook);
  @line = <FILE>;
  close(FILE);

任何想法?我可以按字母顺序排序第一个字段并反转,但似乎无法让第二个字段正确排序。 提前致谢

6 个答案:

答案 0 :(得分:10)

我同意tadmc的担心,即第二个字段,通过空格并不总是姓氏,但回答问题,因为它与第二个字段有关,你可以使用split得到它,你可以这样排序:

简单但非常慢的版本(易于阅读,但每次比较两行时重新拆分每个字段,效率很低)。

@lines = sort { # Compare second fields
    (split " ", $a)[1]
    cmp
    (split " ", $b)[1]
} @lines;

Schwartzian transform版本(与前一版完全相同,只是更快):

@lines = map { # Get original line back
    $_->[0]
} sort { # Compare second fields
    $a->[1] cmp $b->[1]
} map { # Turn each line into [original line, second field]
    [ $_, (split " ", $_)[1] ]
} @lines;

答案 1 :(得分:2)

如果您不介意使用shell,sort -r -k2将按相反顺序对文件进行排序。

答案 2 :(得分:2)

根据Miguel Prz解决方案,我将'cmd'替换为'&lt; =&gt;'。 这对数字很重要。如果使用CMP,那么排序将作为字符串(数字)工作 - 第一个字符是最重要的,然后是第二个,依此类推。如果您有数字:607,8和35,那么CMP会将其排序为:8,607,35。要将其排序为数字,我们使用“&lt; =&gt;”方法和结果将是:607,35,8

use strict;

open my $FILE, '<', 'phonebook';
my @lines = <$FILE>;

my @sorted = sort { 
                my @a = split(/\s+/,$a); 
                my @b = split(/\s+/,$b); 
                $b[1] <=> $a[1] } @lines;

foreach my $item(@sorted) {
    print "$item\n";
}

close $FILE;

答案 3 :(得分:0)

您需要逐行读取文件才能执行此操作。像这样:

my %list;
open(FILE, phonebook);
while(<FILE>){
    my @vals = split(/:/, $_);
    (my $key = $vals[0]) =~ s/(\S+)\s+(.+)/$2 $1/; # split first field, reverse word order
    $list{$key} = $_; #save row keyed on $key
}

foreach my $key(sort {$b cmp $a} keys(%list)){
    print $list{$key};
}

答案 4 :(得分:0)

我认为以Modern Perl方式编写它是有趣的(解决方案是相同的),这是完整的脚本:

use strict;

open my $FILE, '<', 'phonebook';
my @lines = <$FILE>;

my @sorted = sort { 
                my @a = split(/\s+/,$a); 
                my @b = split(/\s+/,$b); 
                $b[1] cmp $a[1] } @lines;

foreach my $item(@sorted) {
    print "$item\n";
}

close $FILE;

答案 5 :(得分:0)

我很惊讶没有人提到这一点,但如果我们正在对电话簿进行排序,我们可能并不真正想要纯ASCII排序。

Bob DeCarlo之前真的属于Ralph Dearborn吗?如果您使用cmp排序,DeCarlo先生将在结果中排​​在第一位。

即使你对案例进行了规范化,你仍然会遇到问题。排序和归档有很多并发症。这些问题的organizations have rules不同handling

由于排序是一项昂贵的操作,因此您需要尽可能快地进行每次比较。这样做的方法是使用最简单的代码进行所有比较。由于cmp本身不会为我们提供所需的结果,因此我们需要为电话簿中的每个项目生成并缓存标准化的排序术语。

因此,假设您已经在阵列中获得了电话簿数据:

sub extract_and_normalize {
     # Do stuff here to embody your alphabetization rules.

     return [ $normed, $line ];   
}

# Generate your sort terms
my @processed = map extract_and_normalize($_), @lines;

# Sort by the normalized values
my @sorted = sort {$a->[0] cmp $b->[0]}, @processed;

# Extract the lines from the sorted set.
@lines = map $_->[1], @sorted;

或者像hobbs建议的那样使用Schwartzian变换来避免产生所有中间变量:

@lines = map $_->[1],
         sort { $a->[0] cmp $b->[0] }
         map extract_and_normalize($_), @lines;