最初の質問に対する短い答え:なぜ書けないのです$json['count'] where $json['id'] = 3
か? PHP はクエリ言語ではないからです。質問を作成する方法は、単純な SQL 選択クエリのように見えます。SQL はそのインデックスをトラバースし、(必要に応じて)テーブル全体のスキャンも実行します。SQL の構造化クエリ言語を使用すると、DBが実行するループをわざわざ書き出す必要がなくなります。
ループを書いていないからループがないというわけではありません (証拠の欠如は不在の証拠ではありません)。
)。すべてをチューリングするつもりはありませんが、マシン レベルでできることは限られています。下位レベルでは、一度に 1 つずつ実行する必要があります。多くの場合、これはインクリメント、チェック、そして再びインクリメントすることを意味します...別名再帰とトラバース。
PHP は、が意味することを理解していると考え、実際には取得したいのに、が参照する値をarrayで$json['id']
返すことを意味していると考えます。を決定するには、ある種のループを作成する必要があります。配列のソートを提案する人もいます。それも、マップ/フィルター/マージする他の関数と同様に、配列全体をループすることを意味します。仕方がない_id
$json
$json[n]['id']
n
array_*
そのあたり。必要なことを正確に実行するすぐに使用できるコア関数はないため、ループを自分で作成する必要があります。
パフォーマンスが重要な場合は、より効率的なループを作成できます。以下に、わずかに少ないブルート ループである半補間検索を示します。ここでも三分探索を使用できます。それを実装することは、あなたが取り組むことができるものです。
for ($i = 1, $j = count($bar), $h = round($j/2);$i<$j;$i+= $h)
{
if ($bar[++$i]->id === $search || $bar[--$i]->id === $search || $bar[--$i]->id === $search)
{//thans to short-circuit evaluation, we can check 3 offsets in one go
$found = $bar[$i];
break;
}//++$i, --$i, --$i ==> $i === $i -1, increment again:
if ($bar[++$i]->id > $search)
{// too far
$i -= $h;//return to previous offset, step will be halved
}
else
{//not far enough
$h = $j - $i;//set step the remaining length, will be halved
}
$h = round($h/2);//halve step, and round, in case $h%2 === 1
//optional:
if(($i + $h + 1) === $j)
{//avoid overflow
$h -= 1;
}
}
$bar
json でデコードされた配列はどこにありますか。
これがどのように正確に機能するかは、このアプローチの欠点と同様に以下に説明されていますが、今のところ、あなたの質問にもっと関連しています:実装方法:
function lookup(array $arr, $p, $val)
{
$j = count($arr);
if ($arr[$j-1]->{$p} < $val)
{//highest id is still less value is still less than $val:
return (object) array($p => $val, 'count' => 0, 'error' => 'out of bounds');
}
if ($arr[$j-1]->{$p} === $val)
{//the last element is the one we're looking for?
return $end;
}
if ($arr[0]->{$p} > $val)
{//the lowest value is still higher than the requested value?
return (object) array($p => $val, 'count' => 0, 'error' => 'underflow');
}
for ($i = 1, $h = round($j/2);$i<$j;$i+= $h)
{
if ($arr[++$i]->{$p} === $val || $arr[--$i]->{$p} === $val || $arr[--$i]->{$p} === $val)
{//checks offsets 2, 1, 0 respectively on first iteration
return $arr[$i];
}
if ($arr[$i++]->{$p} < $val && $arr[$i]->{$p} > $val)
{//requested value is in between? don't bother, it won't exist, then
return (object)array($p => $val, 'count' => 0, 'error' => 'does not exist');
}
if ($arr[++$i]->{$p} > $val)
{
$i -= $h;
}
else
{
$h = ($j - $i);
}
$h = round($h/2);
}
}
$count = lookup($json, 'id', 3);
echo $count['count'];
//or if you have the latest version of php
$count = (lookup($json, 'id', 3))['count'];//you'll have to return default value for this one
個人的には、プロパティと値のペアが見つからない場合は default-object を返さず、 を返すnull
かスローRuntimeException
しますが、それはあなたが決めることです。
ループは基本的に次のように機能します。
$i
各反復で、オフセット$i+1
およびのオブジェクト$i-1
がチェックされます。
オブジェクトが見つかった場合、そのオブジェクトへの参照が割り当てられ$found
、ループが終了します
- オブジェクトが見つかりません。次の 2 つの手順のいずれかを実行します。
- オフセットの ID が探しているものより大きい場合、
$h
オフセットからステップ ( ) を減算し$i
、ステップを半分にします。もう一度ループする
- ID が検索よりも小さい (まだ完了していません): step を配列の残りの長さの半分に変更します。
これがより「賢い」ループ方法である理由を図で示します。
|==========x=============================|//suppose x is what we need, offset 11 of a total length 40:
//iteration 1:
012 //checked offsets, not found
|==========x=============================|
//offset + 40/2 == 21
//iteration 2:
012//offsets 20, 21 and 22, not found, too far
|==========x=============================|
//offset - 21 + round(21/2)~>11 === 12
//iteration 3:
123 //checks offsets 11, 12, 13) ==> FOUND
|==========x=============================|
assign offset-1
break;
11 回の反復ではなく、わずか 3 回の反復で必要なオブジェクトを見つけることができました。このループはいくらかコストがかかりますが (より多くの計算が必要になります)、欠点が利点を上回ることはめったにありません。
ただし、このループにはいくつかの盲点があるため、まれに速度が遅くなりますが、平均するとかなりうまく機能します。100,000 個のオブジェクトを含む配列を使用して id を探し、このループを数回テストしましたがrandom(1,99999)
、平均して .0018ms を管理し、.08ms を超える時間はかかりませんでした。これはまったく悪くありません。
もちろん、オフセットの id と検索された id の差を使用してループを改善するか、オフセット$i
の id が検索値とオフセットの id より大きい場合は中断できます。$i-1
無限ループを避けるため、検索値よりも小さくなっています。ただし、全体として、これはここで提供されている最もスケーラブルでパフォーマンスの高いループアップ アルゴリズムです。