7

不明な数の配列があり、それぞれに不明な数の単語が含まれています。各リストの値を連結して、単語のすべての可能なバリエーションが最終的な配列に格納されるようにします。

たとえば、アレイ1に次のものが含まれている場合:

dog
cat

アレイ2には次のものが含まれます。

food
tooth

アレイ3には次のものが含まれます。

car
bike

出力を次のようにしたいと思います。

dog food car
dog food bike
dog tooth car
dog tooth bike
cat food car
cat food bike
cat tooth car
cat tooth bike

3つ以上のリストが存在する可能性があり、各リストには2つ以上の単語が含まれる可能性があります。

これをPHPで実行したいと思います。

リストの数がわかっていれば、それを行う方法を知っていますが、おそらく最もリソース効率の高い方法ではありません。foreachただし、配列の数がわかっている場合は、ネストされたループが機能します。そうしないとどうなりますか?そして、この問題を解決するためのいくつかの方法は何ですか。たとえば、それぞれ100語の配列が100個ある場合でも機能します。または1000?

ありがとう!

4

4 に答える 4

9

すべての単語配列を1つの配列に入れて、次のような再帰関数を使用できます。

function concat(array $array) {
    $current = array_shift($array);
    if(count($array) > 0) {
        $results = array();
        $temp = concat($array);
        foreach($current as $word) {
          foreach($temp as $value) {
            $results[] =  $word . ' ' . $value;
          }
        }
        return $results;           
    }
    else {
       return $current;
    }
}

$a = array(array('dog', 'cat'), array('food', 'tooth'), array('car', 'bike'));

print_r(concat($a));

どちらが返されますか:

Array
(
    [0] => dog food car
    [1] => dog food bike
    [2] => dog tooth car
    [3] => dog tooth bike
    [4] => cat food car
    [5] => cat food bike
    [6] => cat tooth car
    [7] => cat tooth bike
)

しかし、出力配列が非常に大きくなるため、これは大きな配列ではうまく機能しないと思います。


これを回避するには、同様のアプローチを使用して、組み合わせを直接出力できます。

function concat(array $array, $concat = '') {
    $current = array_shift($array);

    $current_strings = array();

    foreach($current as $word) {
            $current_strings[] = $concat . ' ' . $word;
    }

    if(count($array) > 0) {
        foreach($current_strings as $string) {
            concat($array, $string);
        }       
    }
    else {
      foreach($current_strings as $string) {
          echo $string . PHP_EOL;
      }   
    }
}

concat(array(array('dog', 'cat'), array('food', 'tooth'), array('car', 'bike')));

これは次のようになります。

dog food car
dog food bike
dog tooth car
dog tooth bike
cat food car
cat food bike
cat tooth car
cat tooth bike

このアプローチでは、「サブ連結」を取得することも簡単です。echo $string . PHP_EOL;前に挿入するだけconcat($array, $string);で、出力は次のようになります。

 dog
 dog food
 dog food car
 dog food bike
 dog tooth
 dog tooth car
 dog tooth bike
 cat
 cat food
 cat food car
 cat food bike
 cat tooth
 cat tooth car
 cat tooth bike
于 2010-02-11T18:25:01.040 に答える
5

結果セットの要素を列挙できます。つまり、0 ....(要素の数)-1の間の整数ごとに、返す要素を指定できます(つまり、自然な順序があります)。与えられた例の場合:

0 => array1[0], array2[0], array3[0]
1 => array1[0], array2[0], array3[1]
2 => array1[0], array2[1], array3[0]
7 => array1[1], array2[1], array3[1]

必要なのは、(整数)インデックスnと、インデックスを(自然順序付けされた)セットのn番目の要素に「変換」する関数だけです。現在の状態を格納するために必要なのは整数だけなので、多くの/大きな配列がある場合、メモリ消費は「爆発」しません。クリスが彼のコメントで言ったように、あなたは(より小さなセットを使用するとき)速度を低メモリ消費と交換します。(私は-phpの実装方法-これも合理的な高速ソリューションだと思います。)

$array1 = array('dog', 'cat');
$array2 = array('food', 'tooth');
$array3 = array('car', 'bike');

function foo( $key /* , ... */ ) {
  $params = func_get_args();
  $rv = array();

  $key = array_shift($params);
  $i=count($params);

  while( 0 < $i-- ) {
    array_unshift($rv, $params[$i][ $key % count($params[$i]) ]);
    $key = (int)($key / count($params[$i]));
  }
  return $rv;
}

for($i=0; $i<8; $i++) {
  $a = foo($i, $array1, $array2, $array3);
  echo join(', ', $a), "\n";
}

これを使用して、たとえばIteratorSeekableIterator、またはArrayAccessを実装することができます(これにより、PythonやRubyのように、再帰的なソリューションと比較して制御を反転します)yield

<?php
$array1 = array('dog', 'cat', 'mouse', 'bird');
$array2 = array('food', 'tooth', 'brush', 'paste');
$array3 = array('car', 'bike', 'plane', 'shuttlecraft');
$f = new Foo($array1, $array2, $array3);
foreach($f as $e) {
  echo join(', ', $e), "\n";
}

class Foo implements Iterator {
  protected $data = null;
  protected $limit = null;
  protected $current = null;

  public function __construct(/* ... */ ) {  
    $params = func_get_args();
    // add parameter arrays in reverse order so we can use foreach() in current()
    // could use array_reverse(), but you might want to check is_array() for each element.
    $this->data = array();
    foreach($params as $p) {
      // <-- add: test is_array() for each $p  -->
      array_unshift($this->data, $p);
    }
    $this->current = 0;
    // there are |arr1|*|arr2|...*|arrN| elements in the result set
    $this->limit = array_product(array_map('count', $params));
  }

  public  function current() {
    /* this works like a baseX->baseY converter (e.g. dechex() )
       the only difference is that each "position" has its own number of elements/"digits"
    */
    // <-- add: test this->valid() -->
    $rv = array();
    $key = $this->current;
    foreach( $this->data as $e) {
      array_unshift( $rv, $e[$key % count($e)] );
      $key = (int)($key/count($e));
    }
    return $rv;
  }

  public function key() { return $this->current;  }
  public function next() { ++$this->current; }
  public function rewind () { $this->current = 0; }
  public function valid () { return $this->current < $this->limit; }
}

プリント

dog, food, car
dog, food, bike
dog, food, plane
dog, food, shuttlecraft
dog, tooth, car
dog, tooth, bike
[...]
bird, paste, bike
bird, paste, plane
bird, paste, shuttlecraft

(シーケンスは大丈夫のようです;-))

于 2010-02-12T07:21:30.400 に答える
2

私はこれを巨大な単語リストでテストしていませんが、適度なサイズのリストではかなり高速であり、再帰を使用していません。これはおそらくメモリ制限の問題を引き起こしていると思います(間違っている場合は修正してください)。

$lines = array('');

foreach ($arrays as $array) {

  $old_lines = $lines;
  $lines = array();

  foreach ($array as $word) {

    foreach ($old_lines as $line) {

      $lines[] = trim($line .' '. $word);

    } // foreach

  } // foreach

} // foreach
于 2010-02-11T19:01:37.843 に答える
2

私の見解

class Combinator
{
     protected $words;
     protected $combinator;

     public function __construct($words, $combinator = null)
     {
         $this->words = $words;
         $this->combinator = $combinator;
     }

     public function run($combo = '')
     {
         foreach($this->words as $word) {
             if($this->combinator !== null) {
                 $this->combinator->run("$combo $word"); 
             } else {
                 echo "$combo $word", PHP_EOL;
             }
         }
     }
}

$c = new Combinator(array('dog', 'cat'), 
                    new Combinator(array('food', 'tooth'),
                                   new Combinator(array('car', 'bike'))));

$c->run();
于 2010-02-11T21:18:20.840 に答える