perl 排序问题【实例求教】

perl 排序问题【实例求教】



QUOTE:
__DATA__

月份       电话号码             市话      长途      总话费(元)
-----------------------------------------------------------------------
200809        74889999        3.0        6.6        188
200810        74885444        4.0        1.0        200
200810        74885555        0.8        5.5        120
200810        74889888        4.0        1.0        200

要求:
1,按月份(从小到大)排序。
2,按总花费(从大到小)排序。若总话费相等,则按号码(从小到大)排序

处理后的结果像:

QUOTE:
月份       电话号码             市话      长途      总话费(元)
-----------------------------------------------------------------------
200809        74889999        3.0        6.6        188
200810        74885555        0.8        5.5        120
200810        74885444        4.0        1.0        200
200810        74889888        4.0        1.0        200

其实用excel等也能弄出来,不过我想多熟悉下PERL算法,折腾了好一会儿,构建hash, 然后sort ,还是整不出来。请教大家了,谢谢!

按月份

[Copy to clipboard] [ - ]
CODE:
print map {$_->[1]}
    sort {$a->[0] <=> $b->[0]}
    map {[(split)[0],$_]} <DATA>;
__DATA__
200809        74889999        3.0        6.6        188
200810        74885444        4.0        1.0        200
200810        74885555        0.8        5.5        120
200810        74889888        4.0        1.0        200

按花费

[Copy to clipboard] [ - ]
CODE:
print map {$_->[1]}
    sort {$a->[0] <=> $b->[0]}
    map {[(split)[4],$_]} <DATA>;
__DATA__
200809        74889999        3.0        6.6        188
200810        74885444        4.0        1.0        200
200810        74885555        0.8        5.5        120
200810        74889888        4.0        1.0        200

谢谢,不过您理解错了我的意思,可能我没有表达清楚。

1,按月份(从小到大)排序。
2,按总花费(从大到小)排序。若总话费相等,则按号码(从小到大)排序

首先,按月份排序。同时,按总花费(从大到小)排序,若总话费相等,则按号码(从小到大)排序。并非分2中情况处理。

QUOTE:
摘自《大骆驼》-----貌似这样可以,我再看看
任何可以从 $a 和 $b 中得到的有用信息都可以在一个排序过程中比较的基础来用。比如,如果多行文本要根据特定域来排序,那么可以在排序过程中使用 split 以获取该域:


   @sorted_lines = sort {
      @a_fields = split /:/, $a;      # 冒号分隔的域
      @b_fields = split /:/, $b;
         
      $a_fields[3] <=> $b_fields[3]   # 对第四个域进行能够数字排序,然后
         ||
      $a_fields[0] cmp $b_fields[0]   # 对第一个域进行能够字串排序,然后
         ||
      $b_fields[2] <=> $a_fields[2]   # 对第而个域进行行能够数字反向排序
      ...            # 等等
   } @lines;



QUOTE:
原帖由 mouse.rice 于 2008-12-15 22:01 发表

其实用excel等也能弄出来,不过我想多熟悉下PERL算法,折腾了好一会儿,构建hash, 然后sort ,还是整不出来。请教大家了,谢谢!

把你写的贴出来看看呗
楼上的大大:我大致想法如下(最终结果是错的)
把前4项当key,最后一项当value,构建hash.然后:
sub by_charge_and_number{
        $arr{$b} <=> $arr{$a}
            or
        $a cmp $b;
}

foreach $arrange(sort by_charge_and_number keys %arr)
{
      ......
}


对引用还是不熟悉,这个问题该用引用处理吧


QUOTE:
原帖由 mouse.rice 于 2008-12-15 22:25 发表
我大致想法如下(最终结果是错的)

不要大致想法,要完整的代码,即使它不能给出正确结果。
原来是这样哈
这个可以么

[Copy to clipboard] [ - ]
CODE:
print map {$_->[-1]}
    sort {$a->[0] <=> $b->[0] || $b->[1] <=> $a->[1] || $b->[2] <=> $a->[2]}
    map {[(split)[0,4,1],$_]} <DATA>;
__DATA__
200809        74889999        3.0        6.6        188
200810        74885444        4.0        1.0        200
200810        74885555        0.8        5.5        120
200810        74889888        4.0        1.0        200

大大,那我献丑了:
#!/usr/bin/perl
use strict;
use warnings;

my (%arr, @tem, $arrange);
while (<DATA>)
{
@tem = split /\s+/;
$arr{"$tem[0]\t$tem[1]\t$tem[2]\t$tem[3]"} = $tem[4];
}

sub by_charge_and_number{
        $arr{$b} <=> $arr{$a}
            or
        $a cmp $b;
}

foreach $arrange(sort by_charge_and_number keys %arr)
{
      print "$arrange\t$arr{$arrange}\n";
}

__DATA__
200809        74889999        3.0        6.6        188
200810        74885444        4.0        1.0        200
200810        74885555        0.8        5.5        120
200810        74889888        4.0        1.0        200


结果显然不对,我还是回头看看引用再来
算了,DQP 都给你写好了。。。
呵呵,这晚了,还碰到两位热心的GG。
一并谢了都!晚安,祝两位GG梦到一个美女,最好争的打架