从一组对象中查找最合适的对象

时间:2013-03-22 14:14:49

标签: php arrays loops logic

给定以下结构中的数组(尽管显然还有更多项):

Array
(
    [0] => stdClass Object
        (
            [currency] => 1
            [role] => 3
            [client_company] => 
            [client_group] => 
            [hourly_rate] => 115.00
        )

    [1] => stdClass Object
        (
            [currency] => 1
            [role] => 1
            [client_company] => 
            [client_group] => 
            [hourly_rate] => 115.00
        )

    [2] => stdClass Object
        (
            [currency] => 1
            [role] => 3
            [client_company] => 58
            [client_group] => 
            [hourly_rate] => 110.00
        )
)

我正在尝试创建一个带有四个参数的函数:

  • $角色
  • $货币
  • $ company [可选]
  • $ group [可选]

(“团体”是“公司”的子女:如果指定了团体,则总是会指定母公司)

...这将返回最符合这些参数的项目的“小时费率”值,其依据是:

如果指定$ row,$ currency,$ company和$ group:

  • 找到与角色,货币,公司和群组相匹配的费率。
  • 如果没有,请找一个与角色,货币和公司匹配的
  • 如果没有,请找一个与角色和货币相匹配的
  • 如果没有,则返回FALSE

如果只指定$ row,$ currency和$ company:

  • 找到与角色,货币和公司匹配的费率
  • 如果没有,请找一个与角色和货币相匹配的
  • 如果没有,则返回FALSE

如果只指定$ row和$ currency:

  • 找到与角色和货币匹配的费率
  • 如果没有,则返回FALSE

我得到的是下面的,它的确有效。然而,它像罪一样丑陋。必须有一种更优雅的方式,而不仅仅是将一堆if / else和循环压在一起。然而,现在是星期五,午餐时我吃了太多比萨饼,我的大脑已被奶酪包围了。

你能帮忙吗?

$hourly_rate = FALSE;

if ( !empty($group) && !empty($company) ) {

    foreach ( $rates_cache as $rate ) {

        if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company && (int) $rate->client_group === (int) $group ) {
            $hourly_rate = $rate->hourly_rate;
        }

    }

    if ( empty($hourly_rate) ) {

        foreach ( $rates_cache as $rate ) {

            if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company ) {
                $hourly_rate = $rate->hourly_rate;
            }

        }
    }

    if ( empty($hourly_rate) ) {

        foreach ( $rates_cache as $rate ) {

            if ( $rate->currency == $currency && $rate->role == $role ) {
                $hourly_rate = $rate->hourly_rate;
            }

        }
    }

}else if ( !empty($company) ) {

    foreach ( $rates_cache as $rate ) {

        if ( $rate->currency == $currency && $rate->role == $role && (int) $rate->client_company === (int) $company ) {
            $hourly_rate = $rate->hourly_rate;
        }

    }

    if ( empty($hourly_rate) ) {

        foreach ( $rates_cache as $rate ) {

            if ( $rate->currency == $currency && $rate->role == $role ) {
                $hourly_rate = $rate->hourly_rate;
            }

        }
    }

}else{

    foreach ( $rates_cache as $rate ) {

        if ( $rate->currency == $currency && $rate->role == $role ) {
            $hourly_rate = $rate->hourly_rate;
        }

    }

}

return $hourly_rate;

1 个答案:

答案 0 :(得分:1)

假设

我相信您的cache始终采用以下格式

缓存格式:

$cache = array(
        0 => (object) (array(
                'currency' => 1,
                'role' => 3,
                'client_company' => '',
                'client_group' => '',
                'hourly_rate' => '115.00'
        )),
        1 => (object) (array(
                'currency' => 1,
                'role' => 1,
                'client_company' => '',
                'client_group' => '',
                'hourly_rate' => '115.00'
        )),
        2 => (object) (array(
                'currency' => 1,
                'role' => 3,
                'client_company' => 58,
                'client_group' => '',
                'hourly_rate' => '110.00'
        ))
);

您修改的功能

$param = array(
        "role" => 1,
        "currency" => 1
);

echo find($cache, $param)->hourly_rate;

使用的功能

function find($cache, $param) {
    $mx = array();
    if (! isset($param['role']) || ! isset($param['currency']))
        throw new Exception("Missing Role Or Currency");
    foreach ( $cache as $k => $r ) {
        foreach ( array_keys(array_intersect($param, (array) $r)) as $key ) {
            if ($r->{$key} == $param[$key]) {
                isset($mx[$k]) ? $mx[$k] ++ : $mx[$k] = 1;
            }
        }
    }
    arsort($mx);
    return $cache[key($mx)];
}





更复杂:另一种方法

用法

$param = array(
        "role" => 1,
        "currency" => 1
);

$process = new Process($cache);
echo $process->find($param)->best()->hourly_rate; // Outputs 115.00

多重结果

当找到最合适的时候......你可能会获得多个结果

$param = array(
        "role" => 3,
        "currency" => 1
);

$process = new Process($cache);
var_dump($process->find($param)->results());

输出

array (size=2)
  0 => 
    object(stdClass)[1]
      public 'currency' => int 1
      public 'role' => int 3
      public 'client_company' => string '' (length=0)
      public 'client_group' => string '' (length=0)
      public 'hourly_rate' => string '115.00' (length=6)
  2 => 
    object(stdClass)[3]
      public 'currency' => int 1
      public 'role' => int 3
      public 'client_company' => int 58
      public 'client_group' => string '' (length=0)
      public 'hourly_rate' => string '110.00' (length=6)

未获得最佳效果

如果您正在寻找最便宜的奖品并且致电

,您可以根据您的参数看到您获得2
$param = array(
        "role" => 3,
        "currency" => 1
);

echo Process::quick($cache, $param)->best()->hourly_rate; // returns 115.00 but that is not the cheapest 

解决

解决方案是您可以添加过滤器和sort

$param = array(
        "role" => 3,
        "currency" => 1
);

$sort = function ($a, $b) {
    return $a->hourly_rate < $b->hourly_rate ? - 1 : 1;
};

echo Process::quick($cache, $param)->sort($sort)->best()->hourly_rate; // 110

获取所有相关内容

您也可以循环浏览所有结果并选择您想要获得最佳结果的列

foreach ( Process::quick($cache, $param)->sort($sort)->getColoum("client_company", "hourly_rate") as $result ) {
    print_r($result);
}

输出

stdClass Object
(
    [client_company] => 58
    [hourly_rate] => 110.00
)
stdClass Object
(
    [client_company] => 
    [hourly_rate] => 115.00
)

已更新课程

要添加所有这些附加功能,您需要将课程升级到

    class Process implements JsonSerializable, IteratorAggregate {
    private $cache;
    private $matrix = array();
    private $final = array();

    function __construct($cache) {
        $this->cache = $cache;
    }

    function find($param) {
        if (! isset($param['role']) || ! isset($param['currency']))
            throw new Exception("Missing Role Or Currency");
        foreach ( $this->cache as $k => $rate ) {
            $keys = array_intersect($param, (array) $rate);
            foreach ( array_keys($keys) as $key ) {
                if ($rate->{$key} == $param[$key]) {
                    isset($this->matrix[$k]) ? $this->matrix[$k] ++ : $this->matrix[$k] = 1;
                }
            }
        }
        arsort($this->matrix);
        $this->matrix = array_keys(array_filter($this->matrix, function ($v) {
            return $v >= 2;
        }));
        $this->final = $this->sortArray($this->cache, $this->matrix);
        return $this;
    }

    public static function quick($cache, $param) {
        $process = new Process($cache);
        return $process->find($param);
    }

    public function best() {
        reset($this->final);
        return empty($this->final) ?  : current($this->final);
    }

    public function results() {
        return $this->final;
    }

    public function limit($length = 0) {
        $this->final = array_slice($this->final, 0, $length);
        return $this;
    }

    public function sort(Callable $function) {
        usort($this->final, $function);
        return $this;
    }

    public function getColoum() {
        $arg = array_flip(func_get_args());
        foreach ( $this->final as &$s ) {
            foreach ( $s as $k => $v ) {
                if (! isset($arg[$k]))
                    unset($s->{$k});
            }
        }
        return $this;
    }

    public function getIterator() {
        return new ArrayIterator($this->final);
    }

    public function jsonSerialize() {
        return json_encode($this->final);
    }

    public function __toString() {
        return $this->jsonSerialize();
    }

    private function sortArray(array $array, array $orderArray) {
        $ordered = array();
        foreach ( $orderArray as $key => $value ) {
            array_key_exists($value, $array) and $ordered[$value] = $array[$value];
        }
        return $ordered;
    }
}