简体   繁体   中英

How can I make this PHP function more efficient at scale?

I have no idea how to make this more efficient, and am working through coding challenges. Any hints?

The objective is to return the unique value in an array.

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";

    }

}

The simplest I can come up with is to first use array_count_values() to count the occurrences of each value, then just loop along the result and return the first items that has 1 occurrence. This also returns false if none are found...

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

The array_count_values() will loop across the whole array once (which has to be done in all cases AFAIK), the foreach loop will loop across the result till an item is found.

Edit: If you are going to use objects as the data, you can easily fix this by serializing the data and then following the same process as above. Using unserialize() to return the data...

function solution($a) {
    $ser = array_map("serialize", $a);
    $counts = array_count_values($ser);
    foreach ( $counts as $value => $count ) {
        if ( $count == 1 )  {
            return unserialize($value);
        }
    }
    return false;
}

Ok so I had a different solution (one that continualy destroys the input array), seems about 30% faster then OP's. But then I benched the solution of Nigel Ren and that one rules them all.

EDIT: Except Ren's solution has one caveat. It does not work with non scalars because it uses the values as array keys. While OP's and mine solutions do (if we tweak the array_keys call with a strict=true, what surprised me is that with strict=true it becomes somewhat slower???).

<?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";

Outputs for the various inputs:

// 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
)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM