0

私は次のように構造化された文字列を持っています

(cat,dog,fish) && (drinks) && (milk,water)

次のような配列リストに変換する必要があります

cat drinks milk
cat drinks water
dog drinks milk
dog drinks water
fish drinks milk
fish drinks water

各グループを取得して、次のような配列に挿入するループでそれを行うことを考えました。

0回目のパス:配列を最初の行で埋めます

(cat,dog,fish) && (drinks) && (milk,water)

1回目のパス:最初のグループを検出し、ソースを削除しながら分割します

cat && (drinks) && (milk,water) 
dog && (drinks) && (milk,water) 
fish && (drinks) && (milk,water)

2回目...。

次に、行を分割するたびにこれをループし、最後に追加して元のファイルを削除します。

もっといいアイデアはありますか?そしてPHPでは?

不思議に思う人のためにそれは私が書いている文の構文解析コードの一部です。

ありがとう

4

2 に答える 2

2

通常の文字列解析を使用して、グループ化に対応する3つの配列を取得します。explode()で理解できると思います

次に、3つの配列の「デカルト積」を生成します

$iterators = array(
    new ArrayIterator(array('cat', 'dog', 'fish'))
  , new ArrayIterator(array('drinks'))
  , new ArrayIterator(array('milk', 'water'))
);
$citer = new CartesianProductIterator($iterators);
foreach ($citer as $combo) {
    printf("[%s]\n", join(',', $combo));
}

使用する

class CartesianProductIterator implements Iterator {
    protected $iterators;

    function __construct(array $iters) {
        $this->iterators = $iters;
    }

    function rewind() {
        foreach ($this->iterators as $it) {
            $it->rewind();
        }
    }

    function current() {
        $values = array();
        foreach ($this->iterators as $it) {
            $values[] = $it->current();
        }
        return $values;
    }

    function key() {
        return null;
    }

    function next() {
        /*      
        loop them in reverse, but exclude first
        why? example, odometer: 55199
        you always check the rightmost digit first to see if incrementing it would roll it over and need to be "rewound" to 0, 
        which causes the digit to the left to increase as well, which may also cause it to roll over as well, and so on...
        looping in reverse operates from right column to the left.
        we dont rewind the first column because if the leftmost column is on its last element and needs to roll over
        then this iterator has reached its end, and so rewind() needs to be explicitly called 
        */
        for ($i = count($this->iterators) - 1; $i > 0; --$i) {
            $it = $this->iterators[$i];
            $it->next();
            if ($it->valid()) {
                // were done advancing because we found a column that didnt roll over
                return;
            } else {
                $it->rewind();
            }
        }

        //if execution reached here, then all of the columns have rolled over, so we must attempt to roll over the left most column
        $this->iterators[0]->next();
    }

    function valid() {
        return $this->iterators[0]->valid();
    }
}
于 2012-05-31T20:58:48.517 に答える
1

一度私は同様のセットのすべての組み合わせを作る必要がありました。私は再帰関数を持っていましたが、実際には大きな配列(それぞれ5つのアイテムを含む9つのパーツ)で非常にリソースを消費していましたが、調整を試みることができます:

$input=array(array("cat","dog","fish"),array("drinks"),array("milk","water"));
$output=array();
function combination($string,$level)
{
  global $output;
  global $input;
  if (isset($input[$level]))
  {
    $item=$input[$level];
    if (is_array($item))
    {
      foreach ($item as $i)     
        combination($string." ".$i,$level+1);
    }
    else
      combination($string." ".$item,$level+1);
  }
  else
    $output[]=$string;
}
combination("",0);
var_export($output);

ただし、文字列を入力配列に変換することは別の問題であり、解決方法がわからないため、これを維持します。

于 2012-05-31T20:57:20.437 に答える