Как я могу сделать эту функцию PHP более эффективной в масштабе? - PullRequest
2 голосов
/ 26 октября 2019

Я понятия не имею, как сделать это более эффективным, и работаю над проблемами кодирования. Любые подсказки?

Цель состоит в том, чтобы вернуть уникальное значение в массиве.

Условия проверки, какой код не выполняется

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

    }

}

Ответы [ 2 ]

3 голосов
/ 26 октября 2019

Хорошо, поэтому у меня было другое решение (которое постоянно разрушает входной массив), кажется примерно на 30% быстрее, чем OP. Но затем я рассмотрел решение Найджела Рена, и тот управляет ими всеми.

РЕДАКТИРОВАТЬ: За исключением того, что решение Рена имеет одну оговорку. Он не работает с не скалярами, потому что он использует значения в качестве ключей массива. В то время как OP и мои решения так и делают (если мы настроим вызов array_keys со строгим = true, меня удивит то, что при строгом = 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 голосов
/ 26 октября 2019

Самое простое, что я могу придумать, - это сначала использовать 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() будет зацикливаться по всему массиву один раз (что должно быть сделано во всех случаях AFAIK), цикл foreach будет зацикливатьсяв результате, пока не будет найден элемент.

Редактировать: Если вы собираетесь использовать объекты в качестве данных, вы можете легко исправить это, сериализовав данные, а затем выполнив тот же процесс, что и выше. Использование unserialize() для возврата данных ...

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...