PHPでは、 Array_Walk_Recursiveは、多次元アレイの各要素で何らかの操作を実行する一般的に使用される関数です。この関数は小規模なアレイを扱うときにうまく機能しますが、配列が非常に大きくなるとパフォーマンスが低くなる可能性があります。この記事では、 Array_walk_Recursiveを最適化して、大きな多次元アレイを効率的に処理する方法について説明します。
array_walk_recursiveの基本的な機能は、多次元配列を介して再帰的に反復し、各配列要素にコールバック関数を適用することです。この関数の署名は次のとおりです。
<span><span><span class="hljs-keyword">bool</span></span><span> </span><span><span class="hljs-title function_ invoke__">array_walk_recursive</span></span><span> ( </span><span><span class="hljs-keyword">array</span></span><span> &</span><span><span class="hljs-variable">$array</span></span><span> , </span><span><span class="hljs-keyword">callable</span></span><span> </span><span><span class="hljs-variable">$callback</span></span><span> )
</span></span>
$ array :関数に渡された配列(参照で渡されます)。
$ callback :2つのパラメーターを受け入れるコールバック関数。1つ目は配列の値であり、2つ目は配列のキーです。
たとえば、次のコードは2次元配列で再帰的に動作します。
<span><span><span class="hljs-variable">$array</span></span><span> = [
</span><span><span class="hljs-string">'a'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'b'</span></span><span> => [
</span><span><span class="hljs-string">'c'</span></span><span> => </span><span><span class="hljs-number">2</span></span><span>,
</span><span><span class="hljs-string">'d'</span></span><span> => </span><span><span class="hljs-number">3</span></span><span>
]
];
</span><span><span class="hljs-title function_ invoke__">array_walk_recursive</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function(&</span><span><span class="hljs-variable">$item</span></span><span>, </span><span><span class="hljs-variable">$key</span></span><span>) {
</span><span><span class="hljs-variable">$item</span></span><span> *= </span><span><span class="hljs-number">2</span></span><span>; </span><span><span class="hljs-comment">// 配列内の各要素を掛けます 2</span></span><span>
});
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>
出力の結果は次のとおりです。
<span><span><span class="hljs-title function_ invoke__">Array</span></span><span>
(
[a] => </span><span><span class="hljs-number">2</span></span><span>
[b] => </span><span><span class="hljs-title function_ invoke__">Array</span></span><span>
(
[c] => </span><span><span class="hljs-number">4</span></span><span>
[d] => </span><span><span class="hljs-number">6</span></span><span>
)
)
</span></span>
array_walk_recursiveは非常に簡潔で便利な機能ですが、特に大量のデータを扱う場合は、パフォーマンスのボトルネックもあります。
再帰コールオーバーヘッド: array_walk_recursiveは、多次元配列を横断するための再帰に依存します。各再帰コールは、関数スタックの深さを増加させます。配列のネストされた層が深い場合、スタックオーバーフローまたは性能の低下を引き起こす可能性があります。
繰り返し計算:場合によっては、 array_walk_recursiveが配列の各レイヤーで動作します。操作が複雑であるか、アレイが大きい場合、これはパフォーマンスに大きく影響します。
array_walk_recursiveのパフォーマンスを最適化するために、次の戦略を試すことができます。
まず、再帰処理が必要なアレイレイヤーでのみ動作していることを確認してください。非熟成アレイの場合、 array_walkまたはforeachを直接使用する方が効率的です。例えば:
<span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">optimized_walk</span></span><span>(</span><span><span class="hljs-params">&<span class="hljs-variable">$array</span></span></span><span>) {
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$array</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$key</span></span><span> => &</span><span><span class="hljs-variable">$value</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">is_array</span></span><span>(</span><span><span class="hljs-variable">$value</span></span><span>)) {
</span><span><span class="hljs-title function_ invoke__">optimized_walk</span></span><span>(</span><span><span class="hljs-variable">$value</span></span><span>); </span><span><span class="hljs-comment">// 再帰操作</span></span><span>
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-variable">$value</span></span><span> *= </span><span><span class="hljs-number">2</span></span><span>; </span><span><span class="hljs-comment">// 個々の要素の処理</span></span><span>
}
}
}
</span><span><span class="hljs-variable">$array</span></span><span> = [
</span><span><span class="hljs-string">'a'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'b'</span></span><span> => [
</span><span><span class="hljs-string">'c'</span></span><span> => </span><span><span class="hljs-number">2</span></span><span>,
</span><span><span class="hljs-string">'d'</span></span><span> => </span><span><span class="hljs-number">3</span></span><span>
]
];
</span><span><span class="hljs-title function_ invoke__">optimized_walk</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>
このようにして、 array_walk_recursiveの再帰オーバーヘッドを回避し、再帰の深さをより正確に制御できます。
array_walk_recursiveでは、コールバック関数の最初のパラメーターは配列要素の値です。配列の値を変更する場合は、参照( & )によってパラメーターを渡す必要があります。これには、最適化する際に特別な注意が必要です。
参照を使用する場合、特に大きな配列を扱う場合、メモリコピーオーバーヘッドを減らすことができます。例えば:
<span><span><span class="hljs-title function_ invoke__">array_walk_recursive</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>, function (&</span><span><span class="hljs-variable">$value</span></span><span>, </span><span><span class="hljs-variable">$key</span></span><span>) {
</span><span><span class="hljs-variable">$value</span></span><span> *= </span><span><span class="hljs-number">2</span></span><span>;
});
</span></span>
このようにして、 &$ Value Passは大量のデータ複製を回避し、メモリの使用量を削減します。
各再帰呼び出しは、関数スタックの深さを増加させます。深さが大きすぎると、パフォーマンスの問題が発生し、オーバーフローがスタックされます。したがって、再帰層の数を減らすことは、パフォーマンスの改善に非常に役立ちます。キュー(キュー)またはスタックデータ構造を使用して再帰をシミュレートすることを検討してください。これにより、複数の関数呼び出しやスタック深度の成長を回避できます。
例:
<span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">iterative_walk</span></span><span>(</span><span><span class="hljs-params">&<span class="hljs-variable">$array</span></span></span><span>) {
</span><span><span class="hljs-variable">$stack</span></span><span> = [&</span><span><span class="hljs-variable">$array</span></span><span>]; </span><span><span class="hljs-comment">// スタックを使用して再帰をシミュレートします</span></span><span>
</span><span><span class="hljs-keyword">while</span></span><span> (</span><span><span class="hljs-variable">$stack</span></span><span>) {
</span><span><span class="hljs-variable">$current</span></span><span> = </span><span><span class="hljs-title function_ invoke__">array_pop</span></span><span>(</span><span><span class="hljs-variable">$stack</span></span><span>);
</span><span><span class="hljs-keyword">foreach</span></span><span> (</span><span><span class="hljs-variable">$current</span></span><span> </span><span><span class="hljs-keyword">as</span></span><span> </span><span><span class="hljs-variable">$key</span></span><span> => &</span><span><span class="hljs-variable">$value</span></span><span>) {
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">is_array</span></span><span>(</span><span><span class="hljs-variable">$value</span></span><span>)) {
</span><span><span class="hljs-variable">$stack</span></span><span>[] = &</span><span><span class="hljs-variable">$value</span></span><span>; </span><span><span class="hljs-comment">// それが配列の場合,スタックを押し続けます</span></span><span>
} </span><span><span class="hljs-keyword">else</span></span><span> {
</span><span><span class="hljs-variable">$value</span></span><span> *= </span><span><span class="hljs-number">2</span></span><span>; </span><span><span class="hljs-comment">// 処理要素</span></span><span>
}
}
}
}
</span><span><span class="hljs-variable">$array</span></span><span> = [
</span><span><span class="hljs-string">'a'</span></span><span> => </span><span><span class="hljs-number">1</span></span><span>,
</span><span><span class="hljs-string">'b'</span></span><span> => [
</span><span><span class="hljs-string">'c'</span></span><span> => </span><span><span class="hljs-number">2</span></span><span>,
</span><span><span class="hljs-string">'d'</span></span><span> => </span><span><span class="hljs-number">3</span></span><span>
]
];
</span><span><span class="hljs-title function_ invoke__">iterative_walk</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$array</span></span><span>);
</span></span>
この例では、スタック構造を使用して再帰をシミュレートし、再帰呼び出しのオーバーヘッドを回避します。
タイル張りの多次元配列の場合、配列の構造を知っている場合は、再帰操作の代わりにarray_mapまたはarray_mergeを使用できます。これらの関数は通常、内部的に最適化されているため、 array_walk_recursiveよりも高速です。
たとえば、 array_mapを使用してプロセス配列をバッチバッチします。
<span><span><span class="hljs-variable">$array</span></span><span> = [</span><span><span class="hljs-number">1</span></span><span>, </span><span><span class="hljs-number">2</span></span><span>, </span><span><span class="hljs-number">3</span></span><span>, </span><span><span class="hljs-number">4</span></span><span>];
</span><span><span class="hljs-variable">$result</span></span><span> = </span><span><span class="hljs-title function_ invoke__">array_map</span></span><span>(function(</span><span><span class="hljs-variable">$item</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$item</span></span><span> * </span><span><span class="hljs-number">2</span></span><span>;
}, </span><span><span class="hljs-variable">$array</span></span><span>);
</span><span><span class="hljs-title function_ invoke__">print_r</span></span><span>(</span><span><span class="hljs-variable">$result</span></span><span>);
</span></span>
この方法は、一次元アレイに適していますが、多次元配列を最適化する場合、最初に配列を1次元配列に変換してから、パフォーマンスを大幅に改善することができます。
array_walk_recursiveは非常に強力な機能ですが、大きな配列を処理するのに最適ではありません。不必要な再帰を回避し、参照を使用し、スタックの深さを減らし、他のアレイ操作関数を使用することにより、コードの実行効率を効果的に改善できます。
多次元アレイのトラバーサルパフォーマンスを最適化する場合、再帰コールのオーバーヘッドを減らし、アレイ要素のコピーを複数回回避することが焦点です。大きなアレイに遭遇したときは、反復またはその他のより効率的なソリューションに置き換えられた再帰を検討してください。