快速搜索这个关联数组的php数组

时间:2014-10-04 11:39:15

标签: php arrays search associative-array

我有以下php数组;

array(
    (int) 0 => array(
        'records' => array(
            'id' => '25',
            'parent_id' => '1',
            'address' => '896167',
        )
    ),
    (int) 1 => array(
        'records' => array(
            'id' => '26',
            'parent_id' => '2',
            'address' => '890812',
        )
    ),
    (int) 2 => array(
        'records' => array(
            'id' => '28',
            'parent_id' => '16',
            'address' => '8A3813',
        )
    ),
    (int) 3 => array(
        'records' => array(
            'id' => '29',
            'parent_id' => '17',
            'address' => '8A3914',
        )
    )
)

假设我想找到哪个密钥有'id' => '29',有什么方法可以快速搜索这个数组并返回正确的密钥?在这种情况下,正确的答案是3.

编辑:有人会建议使用foreach循环遍历数组还是使用array_search会更快?或者它们的速度大致相同?

4 个答案:

答案 0 :(得分:2)

foreach ($data as $key => $value) {
    if ($value['records']['id'] == '29') break;
}
echo $key;

线性时间完成。

如果您的数组按ID排序,则可以进行二进制搜索,而不是以对数时间完成。

function binary_search($needle, $haystack) {
    $min = 0;
    $max = count($haystack);
    while ($max >= $min)
    {
        $mid = (int) (($min + $max) / 2);
        if ($haystack[$mid]['records']['id'] == $needle) return $mid;
        else if ($haystack[$mid]['records']['id'] < $needle) $min = $mid + 1;
        else $max = $mid - 1;
    }
    // $needle was not found
    return false;
}

echo binary_search('29', $data);

答案 1 :(得分:1)

您无法在数据结构上使用array_search()。您的foreach解决方案的时间复杂度为O(n)(因此也会array_search()。)

你说记录按其ID排序。然后,您可以使用O(log(n))执行binary search,效果更好。

答案 2 :(得分:1)

你可以使用这样的二进制搜索算法:

$searchableArray = array(
                    0 => array(
                        'records' => array(
                            'id' => '25',
                            'parent_id' => '1',
                            'address' => '896167',
                        )
                    ),
                    1 => array(
                        'records' => array(
                            'id' => '26',
                            'parent_id' => '2',
                            'address' => '890812',
                        )
                    ),
                    2 => array(
                        'records' => array(
                            'id' => '28',
                            'parent_id' => '16',
                            'address' => '8A3813',
                        )
                    ),
                    3 => array(
                        'records' => array(
                            'id' => '29',
                            'parent_id' => '17',
                            'address' => '8A3914',
                        )
                    )
                );

$foundKey = findKey( $searchableArray, 29 );
echo "Found key: " . $foundKey;

function findKey( $searchableArray, $key ){
    $splittedArray = splitArray( $searchableArray );
    if( isInLeftChunk( $splittedArray[0], $key ) ){
        if( ! isOnlyElement( $splittedArray[0] ) ){
            return findKey( $splittedArray[0], $key );
        }
        return key( $splittedArray[0] );
    }
    elseif( isInRightChunk( $splittedArray[1], $key ) ){
        if( ! isOnlyElement( $splittedArray[1] ) ){
            return findKey( $splittedArray[1], $key );
        }
        return key( $splittedArray[1] );
    }

    // Element not found
    return false;
}

function isOnlyElement( $arrayChunk ){
    return count( $arrayChunk ) == 1;
}

function isInLeftChunk( $arrayChunk, $key ){
    end( $arrayChunk );
    $latestKey = key( $arrayChunk );
    if( is_int( $latestKey )){
        return $arrayChunk[ $latestKey ]['records']['id'] >= $key;
    }
    return $arrayChunk[ $latestKey ]['id'] >= $key;
}

function isInRightChunk( $arrayChunk, $key ){
    reset( $arrayChunk );
    $firstKey = key( $arrayChunk );
    if( is_int( $firstKey )){
        return $arrayChunk[$firstKey]['records']['id'] <= $key;
    }
    return $arrayChunk[ $firstKey ]['id'] <= $key;
}

function splitArray( $unsplittedArray ){
    $arrayLenght = count( $unsplittedArray );
    if( $arrayLenght == 1 ){
        return array_chunk( $unsplittedArray, $arrayLenght, true );
    }

    $odd = $arrayLenght % 2 != 0;
    if( $odd ){
        $arrayLenght += 1;
    }
    $arrayLenght = $arrayLenght * 0.5;

    return array_chunk( $unsplittedArray, $arrayLenght, true );
}

答案 3 :(得分:1)

如果要进行许多这样的搜索,最好创建一个反向查找数组。

也就是说,您一次完成缓慢的线性工作 ,之后,它是快速的哈希(关联数组)查找。

一次:

$id2index = array();
foreach ($data as $index => $value) {
    $id2index[$value->id] = $index;
}

已使用多次-查找给定ID的索引:

$index = $id2index[$id];