Chinaunix

标题: [算法] 数据的合并问题 [打印本页]

作者: patagonia2    时间: 2014-10-11 16:21
标题: [算法] 数据的合并问题
遇到这个问题,没什么思路。erlang 版的大圣都不会。
http://bbs.chinaunix.net/thread-4156239-1-1.html
求助        !! perl 版的大圣。

文件A:  大约 60000 行      

Astrakhan       197
Atkarsk 516
Aznakayevo      99
Azov    146
Babayevo        255
Babushkin       202
Bagrationovsk   477
Bakal   451
Baksan  333
Balabanovo      390
Balakhna        459
Balakovo        401
Balashikha      542
Balashov        542
...


文件B:  大约 8000 行      

Q12       207
D23       149
Y11       94
U10       542
Q45       276
A11       482
R08       240
ZAA       250
....


选择数字最接近的

比如

Q12: 207 --> Babushkin: 202

如果最接近的数字有多个 列出所有

比如

U10: 542 --> Balashikha: 542, Balashov: 542


那么输出来的时候,得到结果应该是这样的:

Q12   Babushkin
D23   Azov
Y11   Aznakayevo
U10   Balashov Balashikha
.
.
.

请问各位大圣这种情况怎么处理呢。

作者: 523066680    时间: 2014-10-11 16:43
本帖最后由 523066680 于 2014-10-11 16:47 编辑

有没有更多的数据文本,发一部分到论坛附件,大家方便测试。
还有就是接近的数字,有没有一个限制的阀值。

作者: huang6894    时间: 2014-10-11 16:56
50更接近49还是51?

作者: patagonia2    时间: 2014-10-11 17:07
回复 2# 523066680

谢谢指导。
最接近的数字,没有阀值。 就是最接近的。       
最接近的数字 = abs(A - B)

文件B
ABC 250

文件A
如果没有 250
但是有最接近的数字,251, 249.....
最接近的数字 = abs(A - B)


Astra 251
...
Cakev 249
..
Demak 249

输出
ABC Astra Cakev Demak

谢谢指导。
作者: patagonia2    时间: 2014-10-11 17:10
回复 3# huang6894

谢谢指导。
最接近的数字 = abs(A - B)

abs(50-49) == abs(50-51)
都是最接近的。
谢谢指导。
作者: 523066680    时间: 2014-10-11 19:06
本帖最后由 523066680 于 2014-10-22 21:31 编辑

.............
作者: 523066680    时间: 2014-10-12 13:44
本帖最后由 523066680 于 2014-10-22 21:31 编辑

<代码已删除>
作者: patagonia2    时间: 2015-11-30 15:49
  谢谢指导。
大神们有什么好的代码?
作者: sunzhiguolu    时间: 2015-11-30 15:57
回复 8# patagonia2
遇到这个问题,没什么思路。erlang 版的大圣都不会????




   
作者: stanley_tam    时间: 2015-12-01 21:12
2014年的帖。。居然还有人挖出来了。发帖人还回了。。666
文件A和文件B的第一列数据是惟一没有重复的吗?
作者: MMMIX    时间: 2015-12-01 21:57
回复 8# patagonia2


    你这数据量也不大,直接循环就行了。
作者: sunzhiguolu    时间: 2015-12-02 00:01
回复 1# patagonia2
将你的文件 A,B 各贴出 100 行.
另外, A,B 文件的第二列数值表示什么含义? 峰值, 谷值各是是多少?

   
作者: stanley_tam    时间: 2015-12-02 21:39
来一发
  1. #!perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5. use List::Util qw{max min};

  6. sub main;
  7. sub load_a_data;
  8. sub find_the_nearest;

  9. main;

  10. sub main {
  11.     my $a_data_href = load_a_data();
  12.     my $max = max keys %{$a_data_href};
  13.     my $min = min keys %{$a_data_href};

  14.     # read file B
  15.     my $file = 'B.txt';
  16.     open my $fh, '<', $file or die "Unable to open file $file:$!$/";
  17.     while (defined (my $line = readline $fh) ) {
  18.         # body...
  19.         chomp $line;
  20.         $line =~ s{^\s+ | \s+$}{}gmix;
  21.         next if not $line;

  22.         my ($word, $num) = split /\s+/, $line;
  23.         my $words_aref = find_the_nearest($num, $a_data_href, $max, $min);
  24.         print "$word\t@{$words_aref}$/";
  25.         
  26.     }
  27.     close $fh;
  28. }

  29. sub load_a_data {
  30.     # body...
  31.     my %data = ();
  32.     my $file = 'A.txt';

  33.     open my $fh, '<', $file or die "Unable to open file $file:$!$/";
  34.     while (defined (my $line = readline $fh) ) {
  35.         # body...
  36.         chomp $line;
  37.         $line =~ s{^\s+ | \s+$}{}gmix;
  38.         next if not $line;

  39.         my ($word, $num) = split /\s+/, $line;

  40.         push @{ $data{$num} }, $word;
  41.     }

  42.     close $fh;

  43.     return \%data;
  44. }

  45. sub find_the_nearest {
  46.     # body...
  47.     my ($num, $a_data_href, $max, $min) = @_;
  48.     my $words_aref = [];

  49.     if (exists $a_data_href->{$num}) {
  50.         # if exactly matched
  51.         $words_aref = $a_data_href->{$num};
  52.     }
  53.     else {
  54.         if ($num < $min) {
  55.             # only need to look for numbers greater than $num
  56.             my $new_num = $num;
  57.             while (1) {
  58.                 $new_num += 1;
  59.                 if (exists $a_data_href->{$new_num}) {
  60.                     $words_aref = $a_data_href->{$new_num};
  61.                     last;
  62.                 }
  63.             }
  64.         }
  65.         elsif ($num > $max){
  66.             # only need to look for numbers smaller than $num
  67.             my $new_num = $num;
  68.             while (1) {
  69.                 $new_num -= 1;
  70.                 if (exists $a_data_href->{$new_num}) {
  71.                     $words_aref = $a_data_href->{$new_num};
  72.                     last;
  73.                 }
  74.             }
  75.         }
  76.         else {
  77.             # look for numbers both way
  78.             my $new_num_bigger  = $num;
  79.             my $new_num_smaller = $num;

  80.             while (1) {
  81.                 $new_num_bigger  += 1;
  82.                 $new_num_smaller -= 1;

  83.                 my @words = ();
  84.                 if (exists $a_data_href->{$new_num_bigger}) {
  85.                     push @words, @{ $a_data_href->{$new_num_bigger} };
  86.                 }

  87.                 if (exists $a_data_href->{$new_num_smaller}) {
  88.                     push @words, @{ $a_data_href->{$new_num_smaller} };
  89.                 }

  90.                 if (scalar @words) {
  91.                     $words_aref = \@words;
  92.                     last;
  93.                 }
  94.             }

  95.         }
  96.     }

  97.     return $words_aref;
  98. }


  99. __END__
复制代码

作者: patagonia2    时间: 2015-12-03 09:19
回复 13# stanley_tam

谢谢大圣指导。

偶测试看看
   
   
作者: patagonia2    时间: 2015-12-03 09:22
回复 12# sunzhiguolu


谢谢指导。
第二列数值 > 0
作者: patagonia2    时间: 2015-12-03 09:27
回复 11# MMMIX

谢谢指导。

作者: patagonia2    时间: 2015-12-03 09:30
回复 7# 523066680

大圣为什么删除代码
   
作者: substr函数    时间: 2015-12-03 11:36
回复 13# stanley_tam


   
            while (1) {
                $new_num_bigger  += 1;
                $new_num_smaller -= 1;


方法简单而思路巧妙
确实非常巧妙,赞一个 [ ]

作者: stanley_tam    时间: 2015-12-03 13:10
多谢大神的赞 回复 18# substr函数


   
作者: patagonia2    时间: 2015-12-04 10:20
回复 19# stanley_tam


呵呵,就是这个意思。
非常感谢大圣,程序没有问题。

作者: sunzhiguolu    时间: 2015-12-04 18:50
本帖最后由 sunzhiguolu 于 2015-12-04 19:32 编辑

回复 20# patagonia2
试下: (测试环境: Windows 7)

  1. tr -s [:blank:] < a.txt | sort -t" " -k2n -o a.txt
复制代码
代码如下:

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Tie::File;

  5. my ($sFileA, $sFileB, @aData) = ('File A Path', 'File B Path');
  6. tie (my @aFileA, 'Tie::File', $sFileA, mode => 'O_RDONLY');
  7. open (my $fhFileB, '<', $sFileB);
  8. while (<$fhFileB>){
  9.     my ($sB1, $sB2) = split;
  10.     foreach my $sLine (@aFileA){
  11.         my ($sA1, $sA2) = split /\s+/, $sLine;
  12.         unless (@aData){
  13.             @aData = ($sB1, $sA1, $sA2);
  14.         }else{
  15.             if (abs ($sA2 - $sB2) <= abs ($aData[-1] - $sB2)){
  16.                 if ($aData[-1] == $sA2){
  17.                     @aData = ($aData[0], $aData[1] . ' ' . $sA1, $aData[-1]);
  18.                     next;
  19.                 }
  20.                 $aData[1] = $sA1;
  21.                 $aData[-1] = $sA2;
  22.                 next;
  23.             }
  24.             last;
  25.         }
  26.     }
  27.     printf "%s %s\n", @aData[0,1];
  28.     @aData = ();
  29. }
  30. close ($fhFileB);
复制代码
输出结果如下:

  1. Q12 Babushkin
  2. D23 Azov
  3. Y11 Aznakayevo
  4. U10 Balashikha Balashov
  5. Q45 Babayevo
  6. A11 Bagrationovsk
  7. R08 Babayevo
  8. ZAA Babayevo
复制代码

作者: sunzhiguolu    时间: 2015-12-04 19:08
回复 20# patagonia2
将代码的第 6 行:
'File A Path', 'File B Path' 替换成你自己的文件路径!

   
作者: substr函数    时间: 2015-12-04 20:56
回复 19# stanley_tam


大神 [   ]
加好友
作者: substr函数    时间: 2015-12-04 21:29
回复 13# stanley_tam

大神
大神我想问一个
感觉

如果

  1.         if ($num < $min) {
  2.             # only need to look for numbers greater than $num
  3.             my $new_num = $num;
  4.             while (1) {
  5.                 $new_num += 1;
  6.                 if (exists $a_data_href->{$new_num}) {
  7.                     $words_aref = $a_data_href->{$new_num};
  8.                     last;
  9.                 }
  10.             }
  11.         }
复制代码
可以

  1.         if ($num < $min) {
  2.             $words_aref = $a_data_href->{$min};

  3.         }
复制代码
我的理解哪里有偏差? 还请大神指点...
谢谢大神
   
作者: stanley_tam    时间: 2015-12-05 10:42
多谢大神指点
真是众里寻他千百度,蓦然回首。。。
  1. sub find_the_nearest {
  2.     # body...
  3.     my ($num, $a_data_href, $max, $min) = @_;
  4.     my $words_aref = [];

  5.     if (exists $a_data_href->{$num}) {
  6.         # if exactly matched
  7.         $words_aref = $a_data_href->{$num};
  8.     }
  9.     else {
  10.         if ($num < $min) {
  11.             $words_aref = $a_data_href->{$min};
  12.         }
  13.         elsif ($num > $max){
  14.             $words_aref = $a_data_href->{$max};
  15.         }
  16.         else {
  17.             # look for numbers both way
  18.             my $new_num_bigger  = $num;
  19.             my $new_num_smaller = $num;

  20.             while (1) {
  21.                 $new_num_bigger  += 1;
  22.                 $new_num_smaller -= 1;

  23.                 my @words = ();
  24.                 if (exists $a_data_href->{$new_num_bigger}) {
  25.                     push @words, @{ $a_data_href->{$new_num_bigger} };
  26.                 }

  27.                 if (exists $a_data_href->{$new_num_smaller}) {
  28.                     push @words, @{ $a_data_href->{$new_num_smaller} };
  29.                 }

  30.                 if (scalar @words) {
  31.                     $words_aref = \@words;
  32.                     last;
  33.                 }
  34.             }

  35.         }
  36.     }

  37.     return $words_aref;
  38. }
复制代码
回复 24# substr函数


   




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2