in_array()とPHPの式のどちらが速いですか?
-
11-07-2019 - |
質問
次のことを行う方が速いですか:
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') { ... }
または:
if (!in_array($var, array('test1', 'test2', 'test3', 'test4') { ... }
どちらか一方を実行する方が高速になるポイントがいくつかありますか?
(この場合、2番目のオプションで使用される配列は存在しません。)
解決
i in_array()
を使用することを強くお勧めします。速度の違いは無視できますが、各変数を個別にテストする可読性は恐ろしいです。
ただの楽しみのために、私が実行したテストがあります:
$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
$end = microtime(true);
print "Time1: ". ($end - $start)."<br />";
$start2 = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array) ) {}
}
$end2 = microtime(true);
print "Time2: ".($end2 - $start2)."<br />";
// Time1: 1.12536692619
// Time2: 1.57462596893
注意が必要な些細なメモです。 $ var
が設定されていない場合、方法1はより長くかかります(テストする条件の数によって異なります)
他のヒント
!==
ステートメントの束を置き換える場合は、3番目のパラメーターを in_array
as true
。これにより、配列内の項目の型チェックが強制されます。
通常の!=
はこれを必要としません、明らかに。
前者の方が高速です-後者には多くのオーバーヘッドがあります。配列の作成、関数の呼び出し、配列の検索...
しかし、質問でいくつかの答えを述べたように、早すぎる最適化はすべての悪の根源です。読みやすいようにコードを書き、最適化する必要がある場合は 、プロファイルを作成してから最適化する必要があります。
編集:
@Owenのコードを使用したタイミング(PHP 5.2.6 / windows):
Time1: 1.33601498604
Time2: 4.9349629879
質問のように、ループ内でarray(...)を移動する:
Time1: 1.34736609459
Time2: 6.29464697838
in_arrayは、多数のアイテムの場合に高速になります。 「大」データとコンピューターに関連する多くの要因に基づいて非常に主観的です。あなたが尋ねているので、私はあなたが些細な数のアイテムを扱っていないと思います。長いリストについては、この情報に注意してください。 PHPが線形検索の代わりにハッシュルックアップを利用できるように、反転配列でパフォーマンスを測定します。 「静的」の場合調整する配列はパフォーマンスを改善しないかもしれませんが、そうするかもしれません。
Owenのテストコードを使用して、配列を反転し、より一貫性のある結果を得るために反復を増やします。
$array2 = array_flip($array);
$iterations = 10000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array2[$var])) {}
}
$end = microtime(true);
print "Time3: ".($end - $start)."<br />";
Time1: 12.875
Time2: 13.7037701607
Time3: 3.70514011383
こんにちは、私はこのケースを極端なものにしただけで、値の数が増えるにつれて、単純な比較は 最もパフォーマンスの高い方法ではないことを指摘しました。
ここに私のコードがあります:
$var = 'test';
$num_values = 1000;
$iterations = 1000000;
print "\nComparison performance test with ".$num_values." values and ".$iterations." loop iterations";
print "\n";
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test0' &&
$var != 'test1' &&
// ...
// yes I really have 1000 lines in my file
// ...
$var != 'test999') {}
}
print "\nCase 1: plain comparison";
print "\nTime 1: ". (microtime(true) - $start);
print "\n";
$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
$array1[] = 'test'.$i;
}
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array1) ) {}
}
print "\nCase 2: in_array comparison";
print "\nTime 2: ".(microtime(true) - $start);
print "\n";
$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
$array2['test'.$i] = 1;
}
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array2[$var])) {}
}
print "\nCase 3: values as keys, isset comparison";
print "\nTime 3: ".(microtime(true) - $start);
print "\n";
$start = microtime(true);
$array = array();
for($i=0; $i<$num_values; $i++) {
$array3['test'.$i] = 1;
}
for($i = 0; $i < $iterations; ++$i) {
if (!array_key_exists($var, $array3)) {}
}
print "\nCase 4: values as keys, array_key_exists comparison";
print "\nTime 4: ".(microtime(true) - $start);
print "\n";
私の結果(PHP 5.5.9):
Case 1: plain comparison
Time 1: 31.616894006729
Case 2: in_array comparison
Time 2: 23.226133823395
Case 3: values as keys, isset comparison
Time 3: 0.050863981246948
Case 4: values as keys, array_key_exists comparison
Time 4: 0.13700890541077
同意しますが、これは少し極端ですが、PHPのハッシュテーブルのような連想配列に大きな全体像と大きな可能性があることを示しています。使用するだけです
RoBorgが指摘したように、配列の作成にはオーバーヘッドがあるため、反復ループ内に移動する必要があります。このため、array_flip関数にはオーバーヘッドがあるため、Sparrの投稿も少し誤解を招きます。
5つのバリエーションすべてを含む別の例:
$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
print "Time1: ". (microtime(true) - $start);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array) ) {}
}
print "Time2: ".(microtime(true) - $start);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, array('test1', 'test2', 'test3', 'test4')) ) {}
}
print "Time2a: ".(microtime(true) - $start);
$array2 = array_flip($array);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array2[$var])) {}
}
print "Time3: ".(microtime(true) - $start);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
$array2 = array_flip($array);
if (!isset($array2[$var])) {}
}
print "Time3a: ".(microtime(true) - $start);
私の結果:
Time1 : 0.59490108493 // straight comparison
Time2 : 0.83790588378 // array() outside loop - not accurate
Time2a: 2.16737604141 // array() inside loop
Time3 : 0.16908097267 // array_flip outside loop - not accurate
Time3a: 1.57209014893 // array_flip inside loop
要約すると、 array_flip
(issetを使用)の使用はinarrayよりも高速ですが、単純な比較ほど高速ではありません。
PHPと言えば、次のことを尋ねるとき
- 「if」および「else if」のセット; 、
- &quot; if&quot;一連の「または」条件(元の投稿の詳細など)または
- &quot; in_array&quot;の使用オンザフライで構築された配列
優れている
PHP言語の「スイッチ」は、ステートメントは、そのような状況向けに設計された代替手段であり、より良い答えかもしれません。 (ポスターの例では2つのソリューションを比較するだけですが、実際の質問の見出しではin_arrayとPHPステートメントを検討するように求められているため、これは公正なゲームだと思います)。
ポスターの例では、代わりにお勧めします:
switch ($var)
{ case 'test1': case 'test2': case 'test3': case 'test4':
echo "We have a good value"; break;
default:
echo "We do not have a good value";
}
PHPでは、「または」のコンマなど、いくつかの非プリミティブコンストラクトを許可したいです。しかし、上記は、PHPの設計者がこれを処理する最も明確な方法であると見なしたものです。また、実行時に他の2つの選択肢よりも効率的であるように見えます。
ウィッシュリストについて話している限り、「IN」は投稿者のサンプルの状況では、SQLで見つかったことがさらに明確になります。
このような考え方は、おそらくそのような状況で「in_array」を使用したい人につながるものですが、データ構造を構築してから、そのデータ構造用に設計された述語を使用するのではなく、そのオーバーヘッドが発生することなくそれを言う方法。
こちらは別のケースでのこのベンチのライブアップデートです https://3v4l.org/OA2S7
PHP 7.3の結果:
-
多重比較: 0.0575 07991790771
-
in_array: 0.0256 8507194519
-
array_flip()ループ外測定+ isset(): 0.0146 78001403809
-
array_flip()ループ外の測定されていない+ isset(): 0.0156 50033950806
-
foreachと比較: 0.0627 82049179077
この質問はほぼ10年前のものですが、これを行う方法は他にもあります。 Nickのページ数千のエントリ。信じられないほど高速でした。
foreach(array_values($haystack) as $v)
$new_haystack[$v] = 1;
}
// So haystack becomes:
$arr[“String1”] = 1;
$arr[“String2”] = 1;
$arr[“String3”] = 1;
// Then check for the key:
if (isset($haystack[$needle])) {
echo("needle ".$needle." found in haystack");
}
マイテスト
$array = array('test1', 'test2', 'test3', 'test4');
$var = 'test';
$iterations = 1000000;
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if ($var != 'test1' && $var != 'test2' && $var != 'test3' && $var != 'test4') {}
}
$end = microtime(true);
print "Time1: ". ($end - $start)."<br />";
$start2 = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!in_array($var, $array) ) {}
}
$end2 = microtime(true);
print "Time2: ".($end2 - $start2)."<br />";
$array_flip = array_flip($array);
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array_flip[$var])) {}
}
$end = microtime(true);
print "Time3: ".($end - $start)."<br />";
$start = microtime(true);
for($i = 0; $i < $iterations; ++$i) {
if (!isset($array[$var])) {}
}
$end = microtime(true);
print "Time4: ". ($end - $start)."<br />";
時間1:0.20001101493835
時間2:0.32601881027222
Time3:0.072004079818726
Time4:0.070003986358643