如何使这个PHP函数更高效?

问题描述 投票:2回答:2

我不知道如何提高效率,并且正在努力应对编码挑战。有任何提示吗?

目标是在数组中返回唯一值。

Test Conditions Which Code Fails

function solution($A) {

    foreach ($A as $key => $value) {

        $searchResults = array_keys($A, $value);

        //print "Total number of $value found in Array is: " . count($searchResults) . "\n";

        $checkNumber = count($searchResults);

        if ($checkNumber == 1) {

            //print "Unique value is: $value\n";
            return $value;

        }

        //print "\n";

    }

}
php performance
2个回答
3
投票

好,所以我有一个不同的解决方案(一个连续破坏输入数组的解决方案),似乎比OP快30%。但是后来我把奈杰尔·伦(Nigel Ren)的解决方案作为基准,由所有人来决定。

编辑:除非Ren的解决方案有一个警告。它不适用于非标量,因为它将值用作数组键。尽管OP和我的解决方案都可以(如果我们使用strict = true调整array_keys调用,令我感到惊讶的是,使用strict = true会使它变得更慢?

<?php

function solution(array $A) {

    foreach ($A as $key => $value) {

        $searchResults = array_keys($A, $value, true);

        //print "Total number of $value found in Array is: " . count($searchResults) . "\n";

        $checkNumber = count($searchResults);

        if ($checkNumber == 1) {

            //print "Unique value is: $value\n";
            return $value;

        }

        //print "\n";

    }
    return null;
}

function solutionRen($a) {
    $counts = @array_count_values($a); //disable warning when running over nonscalars
    foreach ( $counts as $value => $count ) {
        if ( $count == 1 )  {
            return $value;
        }
    }
    return false;
}

function solutionSlepic(array $A)
{
    while (!empty($A)) {
        $value = \array_shift($A);

        $keys = \array_keys($A, $value, true);

        if (empty($keys)) {
            return $value;
        }

        foreach ($keys as $key) {
            unset($A[$key]);
        }
    }
    return null;
}

$range = \range(1,20000);
$input = \array_merge($range, $range, [1000001]);
$input = \array_merge([1000001], $range, $range);
$input = \array_merge($range, $range);
$input = \array_merge(\array_fill(0, 20000, 1), \array_fill(0, 20000, 2));

$input = [];
for($i=0; $i<20000; ++$i) {
    $input[$i] = $input[20000 + $i] = new \stdClass();
}
$input[] = (object) ['unique' => true];

$start = \microtime(true);
$solutionOP = solution($input);
$timeOP = \microtime(true) - $start;
echo "OP: $solutionOP ({$timeOP})\n";

$start = \microtime(true);
$solutionRen = solutionRen($input);
$timeRen = \microtime(true) - $start;
echo "Ren: $solutionRen ({$timeRen})\n";

$start = \microtime(true);
$solutionSlepic = solutionSlepic($input);
$timeSlepic = \microtime(true) - $start;
echo "slepic: $solutionSlepic ({$timeSlepic})\n";

各种输入的输出:

// unnique valus is on end
OP: 1000001 (1.7094209194183)
Ren: 1000001 (0.00097393989562988)
slepic: 1000001 (1.1519079208374)

// unique value is the first
OP: 1000001 (0.00011515617370605)
Ren: 1000001 (0.0009620189666748)
slepic: 1000001 (0.00069785118103027)

// unique value not found among 20k distinct values, each twice in the set
OP:  (1.728000164032)
Ren:  (0.00064802169799805)
slepic:  (1.18425989151)

// unque value not found among 2 distinct values, each 20k times in the set
OP:  (6.4909980297089)
Ren:  (0.00011396408081055)
slepic:  (0.0016219615936279)

// 20000 distinct objects, each twice in the array and one unique on end
OP: (4.8111519813538)
stdClass Object
(
    [unique] => 1
)
// Ren's solution is not capable of working with types other then those that can be keys of array, and so it didnt find the solution and instead yells 40k php warning which i have muted.
Ren: (0.013867139816284)
slepic: (2.5294151306152)
stdClass Object
(
    [unique] => 1
)

3
投票

最简单的方法是,首先使用array_count_values()计数每个值的出现次数,然后沿结果循环并返回出现1次的第一个项目。如果未找到,也会返回false ...

function solution($a) {
    $counts = array_count_values($a);
    foreach ( $counts as $value => $count ) {
        if ( $count == 1 )  {
            return $value;
        }
    }
    return false;
}

array_count_values()将循环遍历整个数组一次(在所有情况下都必须这样做),foreach循环将遍历结果直到找到一个项目。

编辑:如果要使用对象作为数据,则可以通过序列化数据然后按照与上述相同的过程轻松解决此问题。使用unserialize()返回数据...

function solution($a) {
    $counts = array_count_values($a);
    foreach ( $counts as $value => $count ) {
        if ( $count == 1 )  {
            return $value;
        }
    }
    return false;
}
© www.soinside.com 2019 - 2024. All rights reserved.