0

我有以下代码:

$json = json_decode(URL, true);
foreach($json as $var)
{
    if($var[id] == $valdefined)
    {
        $number = $var[count];
    }
}

使用 json 它看起来像这样:

 [{"id":"1","count":"77937"},
 {"id":"2","count":"20"},
 {"id":"4","count":"25"},
 {"id":"5","count":"11365"}]

这是 jsondecode 之后数组 ($json) 的样子

 Array ( [0] => Array ( [id] => 1 [count] => 77937 ) [1] => Array ( [id] => 2 [count] => 20 ) [2] => Array ( [id] => 4 [count] => 25 ) [3] => Array ( [id] => 5 [count] => 11365) )

有没有办法说什么是 $json[count] where $json[id] = 3 例如

4

3 回答 3

0

对您最初的问题的简短回答:您为什么不能写作$json['count'] where $json['id'] = 3?仅仅是因为 PHP 不是一种查询语言。您提出问题的方式就像一个简单的 SQL 选择查询。SQL 将遍历其索引,并且(如果需要)也将执行全表扫描,其结构化查询语言仅使您无需费心写出数据库执行的循环。
不是这样的,因为你不写循环,就没有循环(没有证据不是没有证据)。我不会把所有的图灵都放在你身上,但我们只能在机器层面上做很多事情。在较低的级别上,您只需一次迈出一步。通常,这意味着递增、检查和再次递增……AKA 递归和遍历。
PHP 会认为它理解你的意思$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

就个人而言,如果未找到属性值对,我不会返回默认对象,我会返回null或抛出 a RuntimeException,但这由您决定。


循环基本上是这样工作的:

  1. 在每次迭代中,都会检查 offset 和处$i$i+1对象$i-1
    如果找到对象,则分配对其的引用$found并结束循环
  2. 找不到对象。执行以下两个步骤之一:
    • offset 处的 ID 大于我们要查找的 ID,$h从 offset 中减去 step ( ) $i,然后将 step 减半。再次循环
    • ID小于搜索(我们还没有):将步长更改为数组剩余长度的一半

一张图将说明为什么这是一种更“聪明”的循环方式:

|==========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),我没有看到它花费的时间超过 0.08 毫秒,平均而言,它管理 0.0018 毫秒,这一点也不差。
当然,您可以通过使用偏移处的 id 和搜索到的 id 之间的差异来改进循环,或者如果偏移$i处的 id 大于搜索值和偏移处的 id 则中断$i-1小于搜索值以避免无限循环。不过,总的来说,这是迄今为止这里提供的最具可扩展性和性能的循环算法。

在此处检查基本的键盘操作

循环包裹在函数中的键盘

于 2013-08-13T12:39:47.353 回答
0

我不确定是否有更好的方法,但这也很好,只要 JSON 对象不大。php 在循环 JSON 时非常快。如果对象很大,那么您可能需要拆分它。我个人所做的是将我的 JSON 变成一个普通对象数组,对它们进行排序,然后在排序的项目上搜索速度更快。

编辑

json_decode($your_thing, true);将其设置为 true 以使其成为关联数组,然后 id 将是key并且count 将是value。完成此操作后,使用 ID 获取值应该真的很容易而且效率更高。

于 2013-08-12T13:58:44.133 回答
0

如果您将构建 json 对象的方式更改为如下所示:-

{"1":77937,"2":20,"4":25,"5":11365}

然后使用设置为 TRUE 的 json_decode() 参数 2,即将 json 转换为数组。

然后你有一个可用的 assoc 数组,其中 ID 作为键,如下所示:

<?php
    $json = '{"1":77937,"2":20,"4":25,"5":11365}';
    $json_array = json_decode($json, TRUE);
    print_r( $json_array);
?>

导致这个数组

Array
(
    [1] => 77937
    [2] => 20
    [4] => 25
    [5] => 11365
)

你可以做一个简单的

 $number = json_array( $valdefined );

或者更好

if ( array_key_exists( $valdefined, $json_array ) ) {
   $number = json_array( $valdefined );
} else {
   $number = NULL;   // or whatever value indicates its NON-EXISTANCE
}
于 2013-08-12T14:58:41.570 回答