免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
123下一页
最近访问板块 发新帖
查看: 8718 | 回复: 26
打印 上一主题 下一主题

对hash怎么进行排序比较快呢? [复制链接]

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-06-19 17:46 |只看该作者 |倒序浏览
30可用积分
本帖最后由 huang6894 于 2014-06-20 10:51 编辑

在一个perl脚本中,我使用:


  1.   open DATA,"> $outdir/tmp.data" or die "$!";
  2. print DATA "$tran\t$chr\t$pos1\t$pos2\t$genename\t$ave\n";
  3. close DATA;
  4. open DATA,"< $outdir/tmp.data" or die "$!";

  5. ###其实我是觉得这样写挺傻的,又读又写。。。之前是用一个hash数组存放,对其key值(第六列)排序,可是不知道怎么分开相同key值的两条记录。。。push的时候把他们当做一个数组里面两个元素了。。。。


  6. open OUT,"> $outdir/result.data" or die "$!";
  7. my @all = sort { $b->[-1] <=> $a->[-1] } map [split], <DATA>;
  8. my $five = 5 * $#all / 100;
  9. my $FIVE = int $five;
  10. $five = $five != $FIVE ? ( $FIVE + 1 ) : $FIVE;
  11. my @ok = ( [ 0 .. $five - 1 ], [ -$five .. -1 ] );
  12. for my $i ( $five .. $#all ) {
  13.         $all[ $ok[0][-1] ][-1] == $all[$i][-1]
  14.         ? push @{ $ok[0] }, $i
  15.         : last;
  16. }

  17. for my $i ( ( $five + 1 ) .. $#all ) {
  18.         $all[ $ok[-1][0] ][-1] == $all[ -$i ][-1]
  19.         ? unshift @{ $ok[1] }, -$i
  20.         : last;
  21. }

  22. print OUT join( "\t", @{ $all[$_] } ), $/ for map @$_, @ok;
  23. close DATA;
  24. close OUT;

复制代码
以上使用的是@rubyish大神的代码

得到类似于:
  1. NM_000402.3     chrX    153759606       153775233       G6PD    66.5543754674645
  2. NM_001042351.1  chrX    153759606       153775787       G6PD    66.5543754674645
  3. NM_000027.3     chr4    178351929       178363657       AGA     0.994475138121547
复制代码
真实情况是,@{$file{$k}}存放了几十万条记录,我只想知道$k大小在前5%和后5%的那些条目…
希望结果是:
  1. NM_000402.3     chrX    153759606       153775233       G6PD    66.5543754674645  max
  2. NM_001042351.1  chrX    153759606       153775787       G6PD    66.5543754674645  max
  3. NM_000027.3     chr4    178351929       178363657       AGA     0.994475138121547  min
复制代码
***************************************************************************************************
4楼@rubyish大神的代码帮了我大忙,谢谢大神的帮忙,非常感谢@q1208c指出题目的错误,感谢@laputa73大神提供的思路。。。
**************************************************************************************************
我是想对第六列进行排序,如果大小在前5%(向上取整)和后5%(向上取整)的条目,输出该行(min/max),可是对于大数据还是挺慢的,请教一下大神,应该怎么优化呢?

最佳答案

查看完整内容

haishi kan boo dong~

论坛徽章:
7
戌狗
日期:2013-12-15 20:43:38技术图书徽章
日期:2014-03-05 01:33:12技术图书徽章
日期:2014-03-15 20:31:17未羊
日期:2014-03-25 23:48:20丑牛
日期:2014-04-07 22:37:44巳蛇
日期:2014-04-11 21:58:0915-16赛季CBA联赛之青岛
日期:2016-03-17 20:36:13
2 [报告]
发表于 2014-06-19 17:46 |只看该作者
haishi kan boo dong~
  1. #!/usr/bin/perl

  2. my @h = sort { $b->[-1] <=> $a->[-1] } map [split], <DATA>;

  3. my $five = 5 * @h / 100;
  4. my $FIVE = int $five;
  5. $five = $five != $FIVE ? ( $FIVE + 1 ) : $FIVE;

  6. my @ok = ( [ 0 .. $five - 1 ], [ -$five .. -1 ] );

  7. for my $i ( $five .. $#h ) {
  8.     $h[ $ok[0][-1] ][-1] == $h[$i][-1]
  9.       ? push @{ $ok[0] }, $i
  10.       : last;
  11. }

  12. for my $i ( ( $five + 1 ) .. @h ) {
  13.     $h[ $ok[-1][0] ][-1] == $h[ -$i ][-1]
  14.       ? unshift @{ $ok[1] }, -$i
  15.       : last;
  16. }

  17. print join( "\t", @{ $h[$_] } ), $/ for map @$_, @ok;

  18. __DATA__
  19. NM_000015.2     chr8    18248755        18258723        NAT2    18
  20. NM_000017.2     chr12   121163571       121177811       ACADS   21
  21. NM_000019.3     chr11   107992258       108018891       ACAT1   17
  22. NM_001004483.1  chr9    107331449       107332411       OR13C8  10
  23. NM_000016.4     chr1    76190043        76229355        ACADM   8
  24. NM_000018.3     chr17   7123150 7128586 ACADVL  4
  25. NM_000014.4     chr12   9220304 9268558 A2M     4
复制代码

求职 : 软件工程师
论坛徽章:
3
程序设计版块每日发帖之星
日期:2015-10-07 06:20:00程序设计版块每日发帖之星
日期:2015-12-13 06:20:00程序设计版块每日发帖之星
日期:2016-05-05 06:20:00
3 [报告]
发表于 2014-06-19 21:34 |只看该作者
首先生成数据,再排序,然后再计算 5% 的界值,最后再进行替换。想一下子搞定,就是自找麻烦。这种问题问法,感觉是伸手党。

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
4 [报告]
发表于 2014-06-19 22:37 |只看该作者
回复 2# 104359176


    嗯嗯,我也是这么做的,可是因为数据比较大,生成后再排序会消耗很多时间,所以我题目就是,怎么排序,比较快………谢谢,谢谢

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
5 [报告]
发表于 2014-06-20 01:23 |只看该作者
本帖最后由 huang6894 于 2014-06-20 01:35 编辑

回复 4# rubyish


    对不起{(-_-)}~       其实是,@{$file{$k}}存放了几十万条记录,我只想知道$k大小在前5·%和后5%的那些条目…
大神的代码帮了我大忙,谢谢大神的帮忙,谢谢谢谢

论坛徽章:
33
荣誉会员
日期:2011-11-23 16:44:17天秤座
日期:2014-08-26 16:18:20天秤座
日期:2014-08-29 10:12:18丑牛
日期:2014-08-29 16:06:45丑牛
日期:2014-09-03 10:28:58射手座
日期:2014-09-03 16:01:17寅虎
日期:2014-09-11 14:24:21天蝎座
日期:2014-09-17 08:33:55IT运维版块每日发帖之星
日期:2016-04-17 06:23:27操作系统版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-24 06:20:0015-16赛季CBA联赛之天津
日期:2016-05-06 12:46:59
6 [报告]
发表于 2014-06-20 08:37 |只看该作者
这么大的数据量, 还要排序列三次, 我看, 怎么排也快不到哪里去.

可否在第一个循环里就搞定呢.

说实话, 我的perl是自学的, 很多高级特性都不懂. 所以, 实在没办法看懂楼主后两个循环是在做什么.

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
7 [报告]
发表于 2014-06-20 08:53 |只看该作者
回复 6# q1208c


    第一次循环进行排序嘛,然后第二次、第三次是为了取前后5%的值

论坛徽章:
42
19周年集字徽章-周
日期:2019-10-14 14:35:31平安夜徽章
日期:2015-12-26 00:06:30数据库技术版块每日发帖之星
日期:2015-12-01 06:20:002015亚冠之首尔
日期:2015-11-04 22:25:43IT运维版块每日发帖之星
日期:2015-08-17 06:20:00寅虎
日期:2014-06-04 16:25:27狮子座
日期:2014-05-12 11:00:00辰龙
日期:2013-12-20 17:07:19射手座
日期:2013-10-24 21:01:23CU十二周年纪念徽章
日期:2013-10-24 15:41:34IT运维版块每日发帖之星
日期:2016-01-27 06:20:0015-16赛季CBA联赛之新疆
日期:2016-06-07 14:10:01
8 [报告]
发表于 2014-06-20 09:07 |只看该作者
为啥要进行排序?您的需求不是只是输出前5%和后5%?
先计算出门限,一次遍历不就搞定了?
如果输出需要排序,在过滤后的数据再排序不是快得多?(因为就剩10%数据了)

论坛徽章:
8
技术图书徽章
日期:2013-08-22 11:21:28未羊
日期:2015-01-19 22:22:25巳蛇
日期:2014-08-11 16:53:08子鼠
日期:2014-05-29 09:04:44摩羯座
日期:2014-04-11 14:15:07丑牛
日期:2014-01-24 12:41:28金牛座
日期:2013-11-21 17:38:28射手座
日期:2015-01-21 08:50:32
9 [报告]
发表于 2014-06-20 09:25 |只看该作者
回复 8# laputa73


    对呀,我就是想这样。。。可是我做不到 不会~

论坛徽章:
33
荣誉会员
日期:2011-11-23 16:44:17天秤座
日期:2014-08-26 16:18:20天秤座
日期:2014-08-29 10:12:18丑牛
日期:2014-08-29 16:06:45丑牛
日期:2014-09-03 10:28:58射手座
日期:2014-09-03 16:01:17寅虎
日期:2014-09-11 14:24:21天蝎座
日期:2014-09-17 08:33:55IT运维版块每日发帖之星
日期:2016-04-17 06:23:27操作系统版块每日发帖之星
日期:2016-04-18 06:20:00IT运维版块每日发帖之星
日期:2016-04-24 06:20:0015-16赛季CBA联赛之天津
日期:2016-05-06 12:46:59
10 [报告]
发表于 2014-06-20 09:34 |只看该作者
回复 7# huang6894
你第一个循环排序的是 key 呀. 并不是你说的第6列呀.

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP