manu
manu

Reputation: 209

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.

Upvotes: 7

Views: 4026

Answers (12)

slideWXY
slideWXY

Reputation: 1155

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 )

Upvotes: 0

draegtun
draegtun

Reputation: 22570

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

Upvotes: 5

frankc
frankc

Reputation: 11473

Bash solution:

cat file_of_numbers| xargs -n2 seq | sort -nu

Upvotes: 0

owensmartin
owensmartin

Reputation: 393

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-

Upvotes: 8

Hynek -Pichi- Vychodil
Hynek -Pichi- Vychodil

Reputation: 26131

Perl oneliner:

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

Upvotes: 1

Fritz G. Mehner
Fritz G. Mehner

Reputation: 17198

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"

Upvotes: 1

Marcelo Cantos
Marcelo Cantos

Reputation: 185980

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

Upvotes: 6

Lars Haugseth
Lars Haugseth

Reputation: 14881

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

Upvotes: 1

dinco
dinco

Reputation: 1

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

Upvotes: 0

blokeley
blokeley

Reputation: 7065

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.

Upvotes: 0

Space
Space

Reputation: 7259

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

Upvotes: 2

balpha
balpha

Reputation: 50948

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)

Upvotes: 2

Related Questions