Оценка нескольких выражений для определения диапазона числовой переменной в php - PullRequest
1 голос
/ 04 января 2011

Извините, если название сбивает с толку.

У меня есть несколько строковых выражений в массиве, подобных этим:

var1 <= 6  && var1 > 3
var1 > 2  
var1 > 4.5

var2 < 22.5  
var2 >= 14.25  
var2 < 16

Как мне оценить все выражения, чтобы определить:

var1 min
var1 max
var2 min
var2 max

Я понимаю, что с выражениями, которые не "или не равны", я не смогу получить точное значение. Это хорошо.

Ответы [ 5 ]

3 голосов
/ 04 января 2011

Вы пытаетесь сделать простое линейное программирование. SimplexInPHP реализует линейное программирование на PHP, которое вы можете использовать. Смотрите это в действии здесь .

Другой вариант - реализовать решение самостоятельно. Используйте split(), чтобы разбить каждое неравенство на токены. Для каждой переменной вычислите мин / макс, начиная с диапазона [-inf, inf], и обновите его для каждого неравенства. Если оператор начинается с <, тогда обновите max до max(cur_max, value); в противном случае обновите мин до min(cur_min, value).

Вы также должны будете отслеживать, являются ли конечные точки включающими или исключающими. Это можно сделать с логическими значениями is_min_inclusive и is_max_inclusive. Новая конечная точка включается, если оператор оканчивается на =, в противном случае она является исключительной. Обязательно разберитесь со случаем, когда у вас есть x < 1 и x <= 1 (в обоих заказах), в результате чего x < 1.

2 голосов
/ 04 января 2011
<?php 

$string = "var1 <= 6    &&  var1 > 0 && var2 >= 4 && var2 < 200";
//creates an array with the key 'name' and 'min OR 'max'
function parseExpression($expression){
    $parts = preg_split("|( )+|", $expression,3,PREG_SPLIT_NO_EMPTY);

    $result = array('name'=>$parts[0]);
    switch ($parts[1]){
        case '<':
            $parts[2]-=1;
            //NO BREAK <x same as <=(x-1)
        case '<=':
            $result['max'] = $parts[2];
            break;
        case '>':
            $parts[2]+=1;
            //NO BREAK >x same as >=(x+1)
        case '>=':
            $result['min'] = $parts[2];
            break;
        default:
            throw new Exception("format not supported");        
    }
    return $result; 
}

$expressions = explode("&&", $string);
$vars = array();
foreach ($expressions as $expression){
    $parsed = parseExpression($expression);
    $name = array_shift($parsed);
    foreach ($parsed as $key => $value){
        if (array_key_exists($key,$vars[$name])){
            switch ($key){
                case 'min':
                    $vars[$name][$key] = min($vars[$name][$key],$value);
                    break;
                case 'max':
                    $vars[$name][$key] = max($vars[$name][$key],$value);
                    break; 
                default:
            }
            throw new Exception("format not supported");
        }
        else{
            $vars[$name][$key] = $value;    
        }
    }
}

var_dump($vars);

?>
1 голос
/ 04 января 2011
<?php

    $arr = array("var1 <= 6",
    "var1 > 2",
    "var1 > 4.5",

    "var2 < 22.5",
    "var2 >= 14.25", 
    "var2 < 16");

    function find_min_max($arr, $variable) {
        $min = '-inf';
        $max = 'inf';
        while (list($i, $v) = each($arr)) {
            list($var, $rel, $value) = preg_split('/\s+/', $v);
            if ($var != $variable) continue;
            if ($rel == "<" || $rel == "<=") {
                if ($value < $max)
                    $max = $value;
            }
            else if ($rel == ">" || $rel == ">=") {
                if ($value > $min)
                    $min = $value;
            }
        }
        return array($min, $max);
    }
    list($min, $max) = find_min_max($arr, "var1");
    echo "var1 $min - $max \n";
    list($min, $max) = find_min_max($arr, "var2");
    echo "var3 $min - $max \n";
?>
1 голос
/ 04 января 2011

Итак, в вашем примере вы ожидаете, что минимальное значение var1 будет> 4,5, а максимальное <= 6? Рассматривали ли вы изменение структуры данных? </p>

Если, например, ваша структура данных выглядела примерно так:

$limits=array('lte'=>array(6), 'lt'=>array(),'gte'=>array(),'gt'=>(2,4.5);

тогда разбор становится тривиальным. Максимум массивов gt и gte будет минимальным значением, причем> или> = в зависимости от того, из какого массива он получен. Минимум массивов lt и lte будет максимальным значением.

0 голосов
/ 04 января 2011

Я думаю ...

http://php.net/manual/en/function.max.php

http://php.net/manual/en/function.min.php

В примере они показывают числовые строковые выражения (т.е. не только приведенные числа с плавающей точкой или целые числа)

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