(PHP) Как вычислить из строки диапозон значений

+
Дата: 18.08.2006 12:33:23
Есть строка

1-5,10,7-8,20-30,11,15-18

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

Надо

6,9,12-14,19

Т.е. это своего рода инвертация значений.
Пока что приходит в голову это - отсортировать по первому числу и простым перебором.

! Скорость очень важна.
maXmo
Дата: 18.08.2006 12:56:25
а что если взять интервал 1-30 и последовательно выкусывать из него интервальчики?
+
Дата: 18.08.2006 12:59:16
каким образом?

1. Входная строка интервалов может быть динамической.
2. Чтобы определить общие границы (min, max) все равно придется пробежаться по всей строке.
maXmo
Дата: 18.08.2006 13:02:54
1. ну и пофиг.
2. не обязательно. Можно при встрече очередного интервала корректировать концы исходного интервала.
*
Дата: 18.08.2006 13:06:02
+
каким образом?
В цикле.
Anjey aka PM
Дата: 18.08.2006 14:39:27
1. Сортируешь по первой цифре
2. Нормализируешь (исключая взаимоперекрывающиеся интервалы)
3. Получив что-то типа 1-5,9,12-24,27,29,32-40 приводишь его к виду 6-8,10,11,25,26,28,30,31 (или 6-8,10-11,25-26,28,30-31... как душе угодно)

Работы то минут на 10-30 (зависит от скорости кодинга)

Да и работать быстро будет
+
Дата: 24.08.2006 17:48:44
Вот, что получилось, сравнивая соседние диапозоны:

<?php
// input string
$str = '1-5,10,7-8,20-30,11,15-18';

$out = '';

$prev = 0;

$start = 1;

$end = 40;

$sep = "\n";

$timer = array_sum(explode(' ', microtime()));

$arr = explode(',', $str);

natsort($arr);

foreach ($arr as $v)
{
    if (!empty($prev))
    {
        $prev_range = explode('-', $prev);
        $range = explode('-', $v);
        
        $from = isset($prev_range[1]) ? $prev_range[1] : $prev_range[0];
        $to   = $range[0];
        
        if ($to>$from+1)
        {
            $out.= implode($sep, range($from+1, $to-1));
            $out.= $sep;
        }
    }
    else    // first
    {
        $range = explode('-', $v);

        if ($range[0]>1)
        {
            $out.= implode($sep, range(1, $range[0]));
        }
    }

    $prev = $v;
}

$last = array_pop($arr);

$range = explode('-', $last);

$from = isset($range[1]) ? $range[1] : $range[0];

if ($from<$end)
{
    $out.= implode($sep, range($from+1, $end));
}

echo $out.'<br>';

echo "timer: ".round(array_sum(explode(' ', microtime()))-$timer, 4);

function p_r($arr)
{
    echo '<pre>'.print_r($arr, true).'</pre>';
}
?>


6 9 12 13 14 19 31 32 33 34 35 36 37 38 39 40
timer: 0.0003

Можно еще быстрее? :)
Если последовательность будет достаточно большая.
Anjey aka PM
Дата: 24.08.2006 18:52:16
+
12 13 14 ........ 31 32 33 34 35 36 37 38 39 40


а это почему бы не оптимизировать? зачем вообще разбивать, или того задача требует?
+
Дата: 24.08.2006 19:05:19
Не оптимизировать что именно?

В данный момент требуется определить "невошедшие" числа (не диапозоны).
Anjey aka PM
Дата: 24.08.2006 21:59:12
тогда понятно... думал нужны именно диапазоны