Замена рекурсивных строк на PHP - PullRequest
2 голосов
/ 13 ноября 2010

Для проекта, над которым я работаю, у меня есть базовый URI с заполнителями, и я хочу сгенерировать все возможные комбинации из массива возможных значений для каждого заполнителя с использованием PHP.

Конкретнее:

<?php
$uri = "foo/bar?foo=%foo%&bar=%bar%";

$placeholders = array(
  '%foo%' => array('a', 'b'),
  '%bar%' => array('c', 'd'),
  // ...
);

Я бы хотел получить следующий массив:

array(4) {
  [0]=>
  string(23) "foo/bar?foo=a&bar=c"
  [1]=>
  string(23) "foo/bar?foo=a&bar=d"
  [2]=>
  string(19) "foo/bar?foo=b&bar=c"
  [3]=>
  string(19) "foo/bar?foo=b&bar=d"
}

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

Возможно, в эти дни я переутомился, но я застрял в достижении этого просто, и я уверен, что есть простой способ, возможно, даже со встроенными функциями PHP…

Советы? Любая помощь высоко ценится.

Ответы [ 5 ]

4 голосов
/ 13 ноября 2010
    <?php
    function rec($values,$keys,$index,$str,&$result)
    {
    if($index<count($values))
    foreach($values[$index] as $val)
    rec($values,$keys,$index+1,$str.substr($keys[$index],1,strlen($keys[$index])-2)."=".$val."&",$result);
    else
    $result[count($result)] = $str;
    }



// Now for test


    $placeholders = array(
      '%foo%' => array('a', 'b'),
      '%bar%' => array('c', 'd' , 'h'),
    );
    $xvalues = array_values($placeholders) ;
    $xkeys = array_keys($placeholders) ;
    $result = array();  
    rec($xvalues,$xkeys,0,"",$result);  // calling the recursive function
    print_r($result);
    // the result will be:
    Array ( 
    [0] => foo=a&bar=c& 
    [1] => foo=a&bar=d& 
    [2] => foo=a&bar=h& 
    [3] => foo=b&bar=c& 
    [4] => foo=b&bar=d& 
    [5] => foo=b&bar=h& 
    ) 
    ?>

Он обрабатывает неограниченное количество заполнителей и неограниченное количество значений

3 голосов
/ 13 ноября 2010
$uri= "foo/bar?foo=%foo%&bar=%bar%&baz=%baz%";
$placeholders = array(
    '%foo%' => array('a', 'b'),
    '%bar%' => array('c', 'd', 'e'),
    '%baz%' => array('f', 'g')
    );

//adds a level of depth in the combinations for each new array of values
function expandCombinations($combinations, $values)
{
    $results = array();
    $i=0;
    //combine each existing combination with all the new values
    foreach($combinations as $combination) {
        foreach($values as $value) {
            $results[$i] = is_array($combination) ? $combination : array($combination);
            $results[$i][] = $value;
            $i++;
        }
    }
    return $results;
}   

//generate the combinations
$patterns = array();
foreach($placeholders as $pattern => $values)
{
    $patterns[] = $pattern;
    $combinations = isset($combinations) ? expandCombinations($combinations, $values) : $values;
}

//generate the uris for each combination
foreach($combinations as $combination)
{
    echo str_replace($patterns, $combination, $uri),"\n";
}

Идея состоит в том, чтобы перечислить в массиве все возможные комбинации для замен.Функция expandCombination просто добавляет один уровень глубины в комбинации для каждого нового шаблона, чтобы заменить его без рекурсии (мы знаем, как PHP любит рекурсию).Это должно позволить заменить приличное количество шаблонов без повторения на безумной глубине.

2 голосов
/ 13 ноября 2010

Рекурсивное решение:

function enumerate($uri, $placeholders){
    $insts = array();
    if (!empty($placeholders)){
        $key = array_keys($placeholders)[0];
        $values = array_pop($placeholders);

        foreach($values => $value){
            $inst = str_replace($uri, $key, $value);
            $insts = array_merge($insts, (array)enumerate($inst, $placeholders));
        }
        return $insts;
    } else {
        return $uri;
    }
}

Каждый вызов функции выталкивает один заполнитель из массива и перебирает его потенциальные значения, перечисляя все оставшиеся значения заполнителей для каждого. Сложность O (k ^ n), где k - среднее количество замен для каждого заполнителя, а n - количество заполнителей.

Мой PHP немного ржавый; дайте мне знать, если я неправильно понял синтаксис.

1 голос
/ 13 ноября 2010
foreach($placeholders['%foo%'] as $foo){
    foreach($placeholders['%bar%'] as $bar){
      $container[] = str_replace(array('%foo%','%bar%'),array($foo,$bar),$uri);
    }
}
0 голосов
/ 13 ноября 2010

Это работает, но не так элегантно из-за необходимости избавляться от ключей массива заполнителей:

<?php

    /*
     * borrowed from http://www.theserverpages.com/php/manual/en/ref.array.php
     * author: skopek at mediatac dot com 
     */
    function array_cartesian_product($arrays) {
        //returned array...
        $cartesic = array();

        //calculate expected size of cartesian array...
        $size = sizeof($arrays) > 0 ? 1 : 0;

        foreach ($arrays as $array) {
            $size *= sizeof($array);
        }

        for ($i = 0; $i < $size; $i++) {
            $cartesic[$i] = array();

            for ($j = 0; $j < sizeof($arrays); $j++) {
                $current = current($arrays[$j]); 
                array_push($cartesic[$i], $current);    
            }

            //set cursor on next element in the arrays, beginning with the last array
            for ($j = sizeof($arrays) - 1; $j >= 0; $j--) {
                //if next returns true, then break
                if (next($arrays[$j])) {
                    break;
                } else { //if next returns false, then reset and go on with previuos array...
                    reset($arrays[$j]);
                }
            }
        }

        return $cartesic;
    }

    $uri = "foo/bar?foo=%foo%&bar=%bar%";
    $placeholders = array(
        0 => array('a', 'b'), // '%foo%'
        1 => array('c', 'd'), // '%bar%'
    );

    //example
    header("Content-type: text/plain");
    $prod = array_cartesian_product($placeholders);
    $result = array();

    foreach ($prod as $vals) {
        $temp = str_replace('%foo%', $vals[0], $uri);
        $temp = str_replace('%bar%', $vals[1], $temp);
        array_push($result, $temp);
    }

    print_r($result);

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