使用任何脚本语言 - perl,python或shell脚本查找范围中的缺失值

时间:2010-04-28 08:23:32

标签: python perl bash shell

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

输入

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

输出应该是这样的

674 675 677 678 679
2669 2672 2673

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

12 个答案:

答案 0 :(得分:8)

Pure bash。

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

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

答案 1 :(得分:6)

在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'

答案 2 :(得分:5)

的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

答案 3 :(得分:2)

的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)

答案 4 :(得分:2)

示例代码使用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

答案 5 :(得分:1)

红宝石:

$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" "}

答案 6 :(得分:1)

Pure Bash:

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"

答案 7 :(得分:1)

Perl one liner:

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

答案 8 :(得分:0)

在发生异常时修改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

答案 9 :(得分:0)

Shell解决方案使用Bash,sort,uniq&amp; jot(Mac OS X):

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

答案 10 :(得分:0)

Bash解决方案:

cat file_of_numbers| xargs -n2 seq | sort -nu

答案 11 :(得分:0)

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运算符对于比较列表很有用。在您的情况下,您想要找到以下所有元素:

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

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 )