【问题标题】:wildcard array comparison - improving efficiency通配符数组比较——提高效率
【发布时间】:2012-07-21 04:15:19
【问题描述】:

我有两个要比较的数组,我想知道是否有更有效的方法。

第一个数组是用户提交的值,第二个数组是允许的值,其中一些可能包含通配符来代替数字,例如

// user submitted values
$values = array('fruit' => array(
        'apple8756apple333',
        'banana234banana',
        'apple4apple333',
        'kiwi435kiwi'
        ));

//allowed values
$match = array('allowed' => array(
        'apple*apple333',
        'banana234banana',
        'kiwi*kiwi'
        ));

我需要知道第一个数组中的所有值是否都匹配第二个数组中的值。

这是我正在使用的:

// the number of values to validate
$valueCount = count($values['fruit']);

// the number of allowed to compare against
$matchCount = count($match['allowed']);

// the number of values passed validation
$passed = 0;

// update allowed wildcards to regular expression for preg_match
foreach($match['allowed'] as &$allowed)
{
    $allowed = str_replace(array('*'), array('([0-9]+)'), $allowed);
}

// for each value match against allowed values
foreach($values['fruit'] as $fruit)
{
    $i = 0;
    $status = false;
    while($i < $matchCount && $status == false)
    {
        $result = preg_match('/' . $match['allowed'][$i] . '/', $fruit);
        if ($result)
        {
            $status = true;
            $passed++;
        }
        $i++;
    }
}

// check all passed validation
if($passed === $valueCount)
{
    echo 'hurray!';
}
else
{
    echo 'fail';
}

我觉得我可能错过了一个 PHP 函数,它比 foreach 循环中的 while 循环做得更好。还是我错了?

更新:对不起,我忘了说,数字可能出现在值中超过 1 个位置,但只有 1 个通配符。我已经更新了数组来表示这一点。

【问题讨论】:

    标签: php loops foreach while-loop preg-match


    【解决方案1】:

    如果您不想在另一个循环中使用循环,最好将$match 正则表达式分组。

    您可以用更少的代码获得整个功能,这可能比您当前的解决方案更有效:

    // user submitted values
    $values = array(
              'fruit' => array(
                  'apple8756apple',
                  'banana234banana',
                  'apple4apple',
                  'kiwi51kiwi'
                )
              );
    
    
    $match = array(
               'allowed' => array(
                  'apple*apple',
                  'banana234banana',
                  'kiwi*kiwi'
                )
              );
    
    $allowed = '('.implode(')|(',$match['allowed']).')';
    $allowed = str_replace(array('*'), array('[0-9]+'), $allowed);
    
    
    foreach($values['fruit'] as $fruit){
      if(preg_match('#'.$allowed.'#',$fruit))
        $matched[] = $fruit;
    }
    
    print_r($matched);
    

    请看这里:http://codepad.viper-7.com/8fpThQ

    【讨论】:

    • 我真的很喜欢这个解决方案!如果我有大量允许的值,我只能看到一个问题,但这可能会导致我选择的任何解决方案出现问题。
    • 它似乎与 500 多个独特的正则表达式匹配和值一起工作得很好:codepad.viper-7.com/l2RWCh
    • 太棒了,谢谢,我得记下那个网站。
    【解决方案2】:

    尝试将第一个数组中的 /\d+/ 替换为 '*',然后在两个数组之间执行 array_diff()

    编辑:澄清后,这里有一个更精致的方法:

    <?php
        $allowed = str_replace("*", "\d+", $match['allowed']);
        $passed = 0;
        foreach ($values['fruit'] as $fruit) {
            $count = 0;
            preg_replace($allowed, "", $fruit, -1, $count);    //preg_replace accepts an array as 1st argument and stores the replaces done on $count;
            if ($count) $passed++;
        }
        if ($passed == sizeof($values['fruit']) {
            echo 'hurray!';
        } else {
            echo 'fail';
        }
    ?>
    

    上面的解决方案并没有消除对嵌套循环的需要,但它只是让 PHP 执行内部循环,可能更快(实际上应该对其进行基准测试)

    【讨论】:

    • 并非允许的数组中的所有值都包含通配符,有时我可能需要具体说明所以这不起作用:-/此外,值中可能有多组数字,但是最多 1 个通配符,因此这将替换所有出现的数字(我已经更新了我的问题以反映这一点,并感谢您 +1)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 2020-01-30
    • 1970-01-01
    • 2019-12-29
    • 2020-08-09
    • 1970-01-01
    • 2012-03-17
    相关资源
    最近更新 更多