免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: expert1
打印 上一主题 下一主题

文件区间整理问题---悬赏100分 [复制链接]

论坛徽章:
0
51 [报告]
发表于 2010-09-02 17:00 |只看该作者
回复 66# expert1


    恩,受人恩惠,应当以身相许
我只怕代码太恶心,打扰了大家的雅兴,所以先整理下...

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
52 [报告]
发表于 2010-09-02 17:29 |只看该作者
本帖最后由 expert1 于 2010-09-02 17:31 编辑

回复 2# ly5066113


    我发现这个列举然后排序的确效率比较低,很容易卡住。

能否这样,把a.txt的各个section对照穷举出来
比如:
setionx 5
sectionx 6

......
然后和b.txt比较,若是a的数据在b中存在就删除a中的这部分,
  1. delete a[i]
复制代码
。然后把b的数据加到对应a.txt的section里去?因为b的数据是不会改变的。只是a的数据的合并,拆分而已了。

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
53 [报告]
发表于 2010-09-02 17:33 |只看该作者
回复 62# expert1


是的,所有数字都放到数组里了。
要优化也是有办法的,但程序就会变的复杂了。
可以用区间当数组的key
a[20,30]=section1
a[10,19]=section2

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
54 [报告]
发表于 2010-09-02 17:37 |只看该作者
回复 70# expert1


那要看你的实际情况了,如果a中有这样的数据:
section1
1-1000000000
那不还是一样很慢。

论坛徽章:
23
15-16赛季CBA联赛之吉林
日期:2017-12-21 16:39:27白羊座
日期:2014-10-27 11:14:37申猴
日期:2014-10-23 08:36:23金牛座
日期:2014-09-30 08:26:49午马
日期:2014-09-29 09:40:16射手座
日期:2014-11-25 08:56:112015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:0315-16赛季CBA联赛之山东
日期:2017-12-21 16:39:1915-16赛季CBA联赛之广东
日期:2016-01-19 13:33:372015亚冠之山东鲁能
日期:2015-10-13 09:39:062015亚冠之西悉尼流浪者
日期:2015-09-21 08:27:57
55 [报告]
发表于 2010-09-02 17:49 |只看该作者
回复 72# expert1


以区间作为数组的key应该是可以的,明天有时间写一下。
或者楼主可以自己试试?

论坛徽章:
0
56 [报告]
发表于 2010-09-03 09:05 |只看该作者
本帖最后由 ashlv 于 2010-09-03 09:31 编辑

昨晚回去整理了一下,基本上,只要文件内区间没有交集,并且不存在类似7-7这样的区间,其它都还没有发现什么问题
虽然7-7这种类型的也可以处理,但是又要写一大坨代码,所以先不处理了
calx.sh:

  1. t1=$1
  2. t2=$2
  3. t3=$3

  4. #获取2个文件中所需数据 文件名/每行所属section/开闭区间/文件内容
  5. awk 'FS="-";/./{
  6.         a[FNR]=substr($0,0,7)=="section"?$0:a[FNR-1];
  7.         a["v"]=substr(a[FNR],8);
  8.         if(a[FNR]==$1)
  9.                 print a["v"],$1,$1,$1;
  10.         else
  11.                 print a["v"],FILENAME=="'${t2}'"?"x ]":"y [",$1" \n"a["v"],FILENAME=="'${t2}'"?"x [":"y ]",$2;
  12. }' $t1 $t2|
  13. #将数据集中堆放,分离开标题
  14. sort -k4nr -k2|
  15. #排除t1集合外所有可以配对的属于t2的区间
  16. #排除t2集合内所有可以配对的属于t1的区间
  17. #此时t2内有效的点必定落在t1范围内,可以根据范围对t2进行对于t1的section定界
  18. #由于同一文件中不存在交集,重合的点section以t1为准
  19. awk '{
  20.         a[NR]=$1;b[NR]=$2;c[NR]=$3;d[NR]=$4;e[NR]=$0;f[NR]=$2=="x"?f[NR-1]==""?0:f[NR-1]:$1;
  21. }END{
  22.         a["x1"]=0;a["y1"]=0;a["x2"]=1;a["y2"]=1;a["z"]=0;
  23.         for(i in e){
  24.                 if(b[i]=="y"&&c[i]=="["&&b[i-1]=="y"&&c[i-1]=="]") a["y1"]++;
  25.                 if(b[i]=="x"&&c[i]=="["&&a["x1"]>0) a["x1"]--;
  26.                 if(b[i]=="x"&&c[i]=="["&&((b[i-1]=="x"&&c[i-1]=="]")||b[i-1]=="")) a["y2"]++;
  27.                 if(b[i]=="y"&&c[i]=="["&&a["x2"]>0) a["x2"]--;
  28.                 if(b[i]=="y"&&c[i]=="]"&&a["z"]>0) a["z"]--;
  29.                 if((a["x1"]+a["y1"]<2&&a["x2"]+a["y2"]<2)||substr(b[i],0,7)=="section")
  30.                         print f[i],b[i],c[i],d[i];
  31.                 if(b[i]=="x"&&c[i]=="]") a["x1"]++;
  32.                 if(b[i]=="y"&&c[i]=="]"&&a["y1"]>0) a["y1"]--;
  33.                 if(b[i]=="y"&&c[i]=="]") a["x2"]++;
  34.                 if(b[i]=="x"&&c[i]=="]"&&a["y2"]>0) a["y2"]--;
  35.                 if(b[i]=="y"&&c[i]=="[") a["z"]++;       
  36.         }
  37. }'|
  38. #将拥有相同值的数据点合并,以t2为准
  39. sort -k4n -k2|
  40. uniq -f 3|
  41. #格式化列表,供后续使用,并将开区间转换为闭区间
  42. awk '{
  43.         if($3=="[")
  44.                 printf $3" "$2" "$1" "($2=="x"?$4+1:$4)" z ";
  45.         else if($3=="]")
  46.                 printf ($2=="x"?$4-1:$4)" "$1" "$2" "$3" z ";
  47.         else
  48.                 print $0;
  49. }'|
  50. #排除原先开区间中每2个区间中的所有数据点
  51. sed "s/x \][^x]\+\[ x/x \] z \[ x/g"|
  52. #合并所有起点,以最大值的起点为准
  53. sed "s/\][^][]\+\]/\]/g"|
  54. #合并所有终点,以最小值的终点为准
  55. sed "s/\[[^][]\+\[/\[/g"|
  56. #格式化
  57. sed "s/\] z\( \[\)\{0,1\}/#/g"|
  58. sed "s/\[//g"|tr "#" "\n"|
  59. sed "s/ z /-/g"|
  60. sed "s/ [xy] //g"|
  61. sort -k1n -k2r|
  62. #获得t1与t2的差集,输出到t3
  63. awk '{print $2;}'|
  64. awk 'FS="-";{if($2==""||($1<=$2))print $0}'>$t3
  65. #合并t3与t2,即获得结果
  66. awk '{
  67.         a[FNR]=substr($0,0,7)=="section"?$0:a[FNR-1];
  68.         print FILENAME,substr(a[FNR],8),$0;
  69. }' $t3 $t2|
  70. sort -k2r -k4r|
  71. uniq -f 2|
  72. sort -k2r|
  73. awk '{print $3}'
复制代码
在LZ测试数据的基础上增加了更多的边界和交集:

  1. $ cat t1
  2. section1
  3. 5-9
  4. 10-25
  5. 30-30
  6. 200-300
  7. section2
  8. 900-1000
  9. 1950-1960
  10. 500-600
  11. 1100-1240
  12. 700-800
  13. section3
  14. 1300-1400
  15. 1450-1900
  16. 2000-2400
  17. 2500-3000
  18. section6
  19. 20000-21000
  20. section7
  21. 22000-23000
  22. $ cat t2
  23. section4
  24. 1-2
  25. 4-6
  26. 7-10
  27. 500-550
  28. 750-800
  29. 920-950
  30. 1955-1965
  31. 1100-1200
  32. section5
  33. 1250-1500
  34. 1600-1800
  35. 2200-2600
  36. 2999-3100
  37. 3200-3300
  38. section8
  39. 20500-22500
  40. $ ./calx.sh t1 t2 t3
  41. section8
  42. 20500-22500
  43. section7
  44. 22501-23000
  45. section6
  46. 20000-20499
  47. section5
  48. 3200-3300
  49. 2999-3100
  50. 2200-2600
  51. 1600-1800
  52. 1250-1500
  53. section4
  54. 920-950
  55. 750-800
  56. 7-10
  57. 500-550
  58. 4-6
  59. 1955-1965
  60. 1100-1200
  61. 1-2
  62. section3
  63. 2601-2998
  64. 2000-2199
  65. 1801-1900
  66. 1501-1599
  67. section2
  68. 951-1000
  69. 900-919
  70. 700-749
  71. 551-600
  72. 1950-1954
  73. 1201-1240
  74. section1
  75. 200-300
  76. 11-25

复制代码

论坛徽章:
0
57 [报告]
发表于 2010-09-03 09:14 |只看该作者
回复 75# ashlv


学习

论坛徽章:
0
58 [报告]
发表于 2010-09-03 09:59 |只看该作者
回复 77# expert1


    额...
难道是结果有误吗?

论坛徽章:
16
IT运维版块每日发帖之星
日期:2015-08-24 06:20:00综合交流区版块每日发帖之星
日期:2015-10-14 06:20:00IT运维版块每日发帖之星
日期:2015-10-25 06:20:00IT运维版块每日发帖之星
日期:2015-11-06 06:20:00IT运维版块每日发帖之星
日期:2015-12-10 06:20:00平安夜徽章
日期:2015-12-26 00:06:302016猴年福章徽章
日期:2016-02-18 15:30:34IT运维版块每日发帖之星
日期:2016-04-15 06:20:00IT运维版块每日发帖之星
日期:2016-05-21 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-14 06:20:00
59 [报告]
发表于 2010-09-03 10:33 |只看该作者
回复 78# ashlv


    ╮(╯▽╰)╭,我承认我没看明白,太复杂了。佩服你的思路。
PS:看下68,72楼的,若是数据区间不是太大的话,是否可行。

awk -F - 'NR==FNR{
for(i=$2;i<=$3;i++;next}

{for(m=$2;m<=$3;m++)
  delete a[$1 m]
}
END{for (i in a)print a}'

我随便写的,这样要求数据是:
sectionX 100-200
这样的格式。我没验证过,感觉思路应该可行的。

论坛徽章:
0
60 [报告]
发表于 2010-09-03 10:43 |只看该作者
回复 80# expert1


    噢,噶的,报恩失败
看来你那30分我算是白拿了,呵呵

按我的理解,照你的说法,思路还是穷举,只要数值范围跨度不大,我觉得都可以接受的
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP