Как найти пропущенные числа в массиве?

96
19 декабря 2020, 06:40

Есть массив такого содержания:

array (
  0 => '1',
  1 => '2',
  2 => '3',
  3 => '4',
  4 => '5',
  5 => '6',
  6 => '7',
  7 => '8',
  8 => '9',
  9 => '11',
  10 => '12',
  11 => '13',
)

Нужно найти есть ли пропущенное значение в нем, например в этом, после 9 сразу идет 11 , то есть пропущено значение 10

Буду благодарен за полезную информацию.

Answer 1

Если размер массива достаточно большой, а предполагаемое число пропущенных элементов не велико, можно еще и такой вариант.

$data = [1,2,5,6,9,11];
$prev = current($data);
$result = array_reduce($data, function($c, $item) use (&$prev){
                    if($item - $prev > 1){
                        $c = array_merge($c, range($prev + 1, $item - 1));
                    }
                    $prev = $item;
                    return $c;
                }, []);

А если специфика задачи такова, что у нас очень большой массив и получается очень много пропущенных значений (и не очень большом числе самих пропущенных интервалов), что использование функции range тратит не оправдано много памяти, то как по классическому примеру из справки по использованию генераторов можем сделать следующее:

$result =  function($data){
                $prev = current($data);
                $ranges = array_reduce($data, function($c, $item) use (&$prev){
                            if($item - $prev > 1)   $c[] = [$prev+1, $item -1];
                            $prev = $item;
                            return $c;
                          }, []);
                foreach($ranges as list($l, $h)){
                     while($l <= $h) yield $l++;
                }
            };
foreach($result($data) as $x) echo $x, "\n";

в этом случае память будет тратится только на хранение пар значений, обозначающих края пропущенных отрезков.

Answer 2

хотелось бы более продвинутого решения)

$arr = [
    0 => '1',
    1 => '2',
    2 => '3',
    3 => '4',
    4 => '5',
    5 => '6',
    6 => '7',
    7 => '8',
    8 => '9',
    9 => '11',
    10 => '12',
    11 => '13'
];
$temp = range(reset($arr), end($arr));
$diff = array_diff($temp, $arr);
print_r($diff);
Answer 3

Не самое элегантное решение, но рабочее.

    $arr = [1, 2, 5, 6, 7, 9, 11];
    $missedNumbers = [];
    foreach ($arr as $id => $number) {
        if (!isset($arr[$id + 1])) {
            continue;
        }
        if ($arr[$id + 1] - $number !== 1) {
            for ($i = 1; $i < $arr[$id + 1] - $number; $i++) {
                $missedNumbers[] = $arr[$id + 1] - $i;
            }
        }
    }

В цикле for находим недостающие числа.

$missedNumbers содержит следущее:

Array
(
    [0] => 4
    [1] => 3
    [2] => 8
    [3] => 10
)
Answer 4

Мне нужно было найти первое пропущенное значение массива. Хотя в вопросе не указано именно первое, но и не указано, что все пропущенные.

Если нужно искать все пропущенные и оптимизировать расход памяти, то уже есть решение от @teran. Только не забудьте про sort() вначале, если надо пройтись по-порядку. Я его протестировал - отлично работает.

В общем, сделал так:

function missedVal($A) {
    sort($A);
    foreach ($A as $key => $value) {
        if ($key!=0 && $value!=$A[$key-1] && $A[$key-1]!=$value-1) {
        return $A[$key-1]+1;
        break;
        }
    }
}
$A = [1, 2, 4, 1, 2, 7, 9, 3];
echo missedVal($A);

Возвращает - 5, func дошла до первого пропущенного и закончила работу.

READ ALSO
Как загрузить и выгрузить массив из бд?

Как загрузить и выгрузить массив из бд?

У меня в js коде формируется массив dataArr вида [0,4,5,4,7,4,5,27]

113
Печать на термопринтере

Печать на термопринтере

У меня есть принтер jp-5890kЯ печатаю через этот плагин - ссылка

116
Ищу библиотеку для работы с json в которой можно обращаться к элементам с помощью []

Ищу библиотеку для работы с json в которой можно обращаться к элементам с помощью []

Существует ли библиотека JSON, в которой можно обращаться к элементам с помощью []

126
Проблема при докеде Base64

Проблема при докеде Base64

На выходе получаю ???????

116