找到数组中最小的缺失整数

时间:2015-02-24 17:11:22

标签: bash perl awk sed

我正在写一个bash脚本,它需要搜索数组中最小的可用整数并将其管道化为变量。

我知道如何识别数组中的最小或最大整数,但我无法弄清楚如何识别'缺失的'最小整数。

示例数组:

1
2
4
5
6

在这个例子中,我需要3作为变量。

8 个答案:

答案 0 :(得分:5)

使用sed这将是愚蠢的。使用GNU awk,你可以做到

array=(1 2 4 5 6)
echo "${array[@]}" | awk -v RS='\\s+' '{ a[$1] } END { for(i = 1; i in a; ++i); print i }'

...记住所有数字,然后从1开始计算,直到找到一个它不记得并打印出来的数字。然后你可以用bash记住这个数字

array=(1 2 4 5 6)
number=$(echo "${array[@]}" | awk -v RS='\\s+' '{ a[$1] } END { for(i = 1; i in a; ++i); print i }')

但是,如果您已经在使用bash,那么您可以在纯粹的bash中做同样的事情:

#!/bin/bash

array=(1 2 4 5 6)

declare -a seen
for i in ${array[@]}; do
    seen[$i]=1
done

for((number = 1; seen[number] == 1; ++number)); do true; done

echo $number

答案 1 :(得分:1)

您可以从最小数字迭代到最大数字并获取第一个不存在的元素

use List::Util qw( first );

my @arr = sort {$a <=> $b} qw(1 2 4 5 6);
my $min = $arr[0];
my $max = $arr[-1];

my %seen;
@seen{@arr} = ();
my $first = first { !exists $seen{$_} } $min .. $max;

答案 2 :(得分:1)

此代码将按您的要求执行。它可以通过二进制搜索轻松加速,但以这种方式最清楚地说明了。

数组的第一个元素可以是任何整数,子例程返回序列中不存在的第一个值。如果完整数组是连续的,则返回undef

use strict;
use warnings;
use 5.010;

my @data = qw/ 1 2 4 5 6 /;
say first_missing(@data);

@data = ( 4 .. 99, 101 .. 122 );
say first_missing(@data);

sub first_missing {

  my $start = $_[0];

  for my $i ( 1 .. $#_ ) {
    my $expected = $start + $i;
    return $expected unless $_[$i] == $expected;
  }

  return;
}

<强>输出

3
100

答案 3 :(得分:1)

这是Perl one liner:

$ echo '1 2 4 5 6' | perl  -lane '} 
           {@a=sort { $a <=> $b } @F; %h=map {$_=>1} @a; 
            foreach ($a[0]..$a[-1]) { if (!exists($h{$_})) {print $_}} ;'

如果要从管道切换到文件输入:

$ perl  -lane '}
           {@a=sort { $a <=> $b } @F; %h=map {$_=>1} @a; 
           foreach ($a[0]..$a[-1]) { if (!exists($h{$_})) {print $_}} ;' file

由于它在过程中被排序,因此输入可以是任意顺序。

答案 4 :(得分:0)

$ cat tst.awk
BEGIN {
    split("1 2 4 5 6",a)
    for (i=1;a[i+1]==a[i]+1;i++) ;
    print a[i]+1
}

$ awk -f tst.awk
3

答案 5 :(得分:0)

这里有一个bash解决方案(假设数字在文件中,每行一个):

sort -n numbers.txt | grep -n . |
grep -v -m1 '\([0-9]\+\):\1' | cut -f1 -d:

第一部分对数字进行排序,然后为每个数字添加一个序列号,第二部分找到第一个与数组中的数字不对应的序列号。

同样的事情,使用sort和awk(沼泽标准,也没有扩展):

sort -n numbers.txt | awk '$1!=NR{print NR;exit}'

答案 6 :(得分:0)

@Borodin's excellent answer

#!/usr/bin/env perl

use 5.020; # why not?
use strict;
use warnings;

sub increasing_stream {
    my $start = int($_[0]);
    return sub {
        $start += 1 + (rand(1) > 0.9);
    };
}

my $stream = increasing_stream(rand(1000));

my $first = $stream->();
say $first;
while (1) {
    my $next = $stream->();
    say $next;
    last unless $next == ++$first;
    $first = $next;
}

say "Skipped: $first";

输出:

$ ./tyu.pl
381
382
383
384
385
386
387
388
389
390
391
392
393
395
Skipped: 394

答案 7 :(得分:0)

此处其他答案设置的主题略有不同。输入的值不一定要预先排序:

$ cat test
sort -nu <<END-OF-LIST |
1
5
2
4
6
END-OF-LIST
awk 'BEGIN { M = 1 } M > $1 { next } M == $1 { M++; next }
       M < $1 { exit } END { print M }'
$ sh test
3

注意:

  • 如果数字已预先排序,请不要理会。
  • 如果没有缺少的数字,则输出下一个更高的数字。
  • 在此示例中,here文档提供了数字,但是一个人可以使用文件或管道。
  • M可能从大于最小的M开始,以忽略阈值以下的丢失数字。
  • 要以最低编号自动开始搜索,请将BEGIN { M = 1 }更改为NR == 1 { M = $1 }