7


2

PHPでn個の配列の値を連結する

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

たとえば、配列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 Answer


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


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_と、インデックスを(自然な順序付けられた)セットのnth要素に「変換」する関数です。 現在の状態を保存するために必要なのは整数のみであるため、多数の/大きな配列がある場合、メモリ消費は「爆発」しません。 クリスが彼のコメントで言ったように、メモリ消費量を減らすために速度を犠牲にします(より小さなセットを使用する場合)。 (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";
}

これを使用して、たとえば Iterator、http://docs.php.net/class.seekableiterator[SeekableIterator]、またはhttp://docs.php.netclass.arrayaccessでさえも[ArrayAccess](およびそれにより、再帰的なソリューションと比較してコントロールを反転します。_almost_は、Pythonまたはrubyの `yield`のようです)

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

(シーケンスは問題ないようです;-))


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


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();