开发者

finding the missing values in a range using any scripting language - perl, python or shell script

I got stuck in one problem of finding the missing values in a range and the range is also variable for the successive rows.

input

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

output should be开发者_如何学编程 like this

674 675 677 678 679
2669 2672 2673

This is just one part and the row values can be more also If you need any clarification, please let me know.


Pure bash.

Use two subshells and run a diff, then clean up the results.

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


In 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

Note: all_numbers is a bit of a lie, since the range excludes the final number, but since that number is guaranteed to be in the set, it doesn't affect the correctness of the algorithm.

Note: I removed the [-1] from my original answer, since int(n) doesn't care about the trailing '\n'.


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


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)


Sample code Using 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

OUTPUT

674 675 677 678 679 2669 2672 2673


Ruby:

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

Golf version (79 characters):

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


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"


Perl oneliner:

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


Modification of Marcelo's solution with safe release of file handle in the event of an exception:

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)

This also avoids using the builtin name file.


Shell solution using Bash, sort, uniq & 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


Bash solution:

cat file_of_numbers| xargs -n2 seq | sort -nu


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 )

You have your list. Set operator is useful for comparing lists. In your case you want to find all elements that:

  • are between the first value and the last one
  • have been passed ( discontinuity)

Set operator generates all uniques values coming from a list

To select all values that are in tot but not in a just do tot - a. Just format the output as a list

if you want to conserve a as a list you need to use copy() in your function:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜