【问题标题】:finding the missing values in a range using any scripting language - perl, python or shell script使用任何脚本语言(perl、python 或 shell 脚本)查找范围内的缺失值
【发布时间】:2011-02-13 05:50:34
【问题描述】:

我遇到了一个问题,即在一个范围内查找缺失值,并且该范围对于连续的行也是可变的。

输入

673 673 673 676 676 680 2667 2667 2668 2670 2671 2674

输出应该是这样的

674 675 677 678 679 2669 2672 2673

这只是一部分,行值还可以更多 如果您需要任何澄清,请告诉我。

【问题讨论】:

    标签: python perl bash shell


    【解决方案1】:

    纯 bash。

    使用两个子shell并运行diff,然后清理结果。

    diff <(cat my_range_with_holes) <(seq 1 1000) | grep '>' | cut -c 3-
    

    【讨论】:

      【解决方案2】:

      在 Python 中:

      def report_missing_numbers(f):
          for line in f:
              numbers = [int(n) for n in line.split()]
              all_numbers = set(range(numbers[0], numbers[-1]))
              missing = all_numbers - set(numbers)
              yield missing
      

      注意:all_numbers有点假,因为范围不包括最终的数字,但由于该数字保证在集合中,不影响正确性算法。

      注意:我从原始答案中删除了 [-1],因为 int(n) 不关心尾随的 '\n'

      【讨论】:

      • 您的代码只从输入中读取了一行。顺便说一句,file 是内置名称,请勿将其用作变量。
      • 是的,你可以。顺便说一句,不带参数的.split() 不会因意外的双空格而中断:'1 2'.split() -> ['1', '2']'1 2'.split(' ') -> ['1', '', '2']int() 不适用于空字符串。
      • 酷!感谢您在split() 上回复投票和提示。在昏暗的过去的某个时候,我曾经知道,但我忘记了。
      【解决方案3】:

      Perl:

      use Modern::Perl;
      
      for my $line (<DATA>) {
          chomp $line;
          my @numbers     = split /\s+/, $line;
          my ($min, $max) = (sort { $a <=> $b } @numbers)[0, -1];
          my @missing     = grep { not $_ ~~ @numbers } $min .. $max;
          say join " ", @missing;
      }
      
      __DATA__
      673 673 673 676 676 680
      2667 2667 2668 2670 2671 2674
      

      【讨论】:

        【解决方案4】:

        Python:

        for line in open("inputfile.txt"):
            vals = set(map(int, line.split()))
            minv, maxv = min(vals), max(vals)
            missing = [str(v) for v in xrange(minv + 1, maxv) if v not in vals]
            print " ".join(missing)
        

        【讨论】:

        • 这工作正常,非常感谢。如果可能的话,你能解释一下吗?
        • @manu:代码非常线性。读取输入(跳过重复项(为什么?)),转换为整数;得到最小值,最大值;从最小值迭代到最大值,跳过输入中的值,从中列出字符串;加入列表以制作单个字符串。
        • @bp:转换为集合更多的是用于列表理解中的查找,而不是删除欺骗。我承认这并不完全是结果。如果只有几个值,那并不重要;如果有很多,可能会使用itertools.imap 而不是map
        【解决方案5】:

        使用 Perl 的示例代码:

        #!/usr/bin/perl
        use strict;
        use warnings;
        
        my @missing;
        
        while(<DATA>) {
            my @data = split (/[ ]/, $_);
            my $i = shift @data;
            foreach (@data) {
                if ($_ != ++$i) {
                       push @missing, $i .. $_ - 1;
                       $i = $_;
                }
            }
        }
        
        print join " ", @missing;
        
        __DATA__
        673 673 673 676 676 680
        2667 2667 2668 2670 2671 2674
        

        输出

        674 675 677 678 679 2669 2672 2673
        

        【讨论】:

          【解决方案6】:

          鲁比:

          $stdin.each_line do |line|
            numbers = line.scan(/\d+/).map(&:to_i)
            missing = (numbers.min..numbers.max).to_a - numbers
            puts missing.join " "
          end
          

          高尔夫版(79 个字符):

          puts $stdin.map{|l|n=l.scan(/\d+/).map(&:to_i);((n.min..n.max).to_a-n).join" "}
          

          【讨论】:

            【解决方案7】:

            纯猛击:

            while read -a line ; do
              firstvalue=${line[0]}
              lastvalue=${line[${#line[@]}-1]}
              output=()
              # prepare the output array
              for (( item=firstvalue; item<=lastvalue; item++ )); do
                output[$item]=1
              done
              # unset array elements with an index from the input set
              for item in ${line[@]}; do
                unset  "output[$item]"
              done
              # echo the remaining indices
              echo -e "${!output[@]}"
            done < "$infile"
            

            【讨论】:

              【解决方案8】:

              Perl 单行器:

              perl -anE'($a,$b)=@F[0,-1];$,=" ";@h{@F}=();say grep!exists$h{$_},$a..$b'
              

              【讨论】:

                【解决方案9】:

                修改 Marcelo 的解决方案,在发生异常时安全释放文件句柄:

                with open('myfile.txt') as f:
                    numbers = [int(n) for n in f.readline()[:-1].split(' ')]
                all_numbers = set(range(numbers[0], numbers[-1]))
                missing = all_numbers - set(numbers)
                

                这也避免了使用内置名称file

                【讨论】:

                  【解决方案10】:

                  使用 Bash、sort、uniq 和 jot (Mac OS X) 的 Shell 解决方案:

                  numbers="673 673 673 676 676 680"
                  numbers="2667 2667 2668 2670 2671 2674"
                  sorted=($(IFS=$'\n' echo "${numbers}" | tr " " '\n' | sort -u ))
                  low=${sorted[0]}
                  high=${sorted[@]: -1}
                  ( printf "%s\n" "${sorted[@]}"; jot $((${high} - ${low} + 1)) ${low} ${high} ) | sort | uniq -u
                  

                  【讨论】:

                    【解决方案11】:

                    Bash 解决方案:

                    cat file_of_numbers| xargs -n2 seq | sort -nu
                    

                    【讨论】:

                    • 这会列出从最小到最大的所有个数字,而不仅仅是缺少的数字。
                    【解决方案12】:
                    a = [ 673, 673, 673, 676, 676, 680]
                    
                    def woo(a):
                        max_, min_ = a[0:-1]
                        a = set(a)
                    
                        tot = set(list(range(min_,max_+1)))
                        return list( tot - a )
                    

                    你有你的清单。 集合运算符对于比较列表很有用。在您的情况下,您希望找到以下所有元素:

                    • 介于第一个值和最后一个值之间
                    • 已通过(不连续)

                    Set 运算符生成来自列表的所有唯一值

                    要选择tot 中但不在a 中的所有值,只需执行tot - a。只需将输出格式化为列表

                    如果您想将a 保存为一个列表,您需要在您的函数中使用copy()

                    a = [ 673, 673, 673, 676, 676, 680]
                    
                    def woo(a):
                        max_, min_ = a[0:-1]
                        a = set(a.copy())
                    
                        tot = set(list(range(min_,max_+1)))
                        return list( tot - a )
                    

                    【讨论】:

                      猜你喜欢
                      • 2015-10-10
                      • 2012-07-06
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2010-10-22
                      • 1970-01-01
                      • 2016-12-10
                      相关资源
                      最近更新 更多