Weedpacket;10994104 wrote:Note that using 1 for the second parameter when counting the characters in $candidate means the loop will have far fewer elements to iterate over.
Ah crap, forgot to update that too. Initially, I had reversed the behavior between mode 0 (the default) and mode 1 in my head; while editing my post, I forgot to switch to using mode 1 in both code samples for the 'guessed' parameter. My mistake!
On the same topic, however, wouldn't your code generate E_NOTICE level errors if the 'guessed' parameter contained characters that were not present in the 'jumbled' one (hence why I included isset() in the relevant coding example)?
At any rate, I managed (after much searching) to locate a sample framework I'd written ages ago to test a series of functions for performance across a set of parameters. Overkill? Yes. But I was bored (both then and now :p), so here is the source:
<?php
/**************
* Test setup *
**************/
$funcs = array('check_valid_guess_rev_1', 'check_valid_guess_rev_2', 'check_valid_guess_rev_3');
$params = array(
array('APEC', 'PEACE'),
array('APEC', 'SPACES'),
array('TOM MARVOLO RIDDLE', 'I AM LORD VOLDEMORT')
);
$num_times = 25000;
$unit_conv = array(1000, 'msec');
$precision = 6;
$sound = true;
/*****************************************
* Definitions of functions to be tested *
*****************************************/
function check_valid_guess_rev_1($jumbled, $guess)
{
$jumbled_freq = count_chars($jumbled, 1);
foreach(count_chars($guess, 1) as $char => $freq)
if(!isset($jumbled_freq[$char]) || $freq > $jumbled_freq[$char])
return false;
return true;
}
function check_valid_guess_rev_2($jumbled, $guess)
{
$jumbled_freq = count_chars($jumbled);
foreach(count_chars($guess, 1) as $char => $freq)
if($freq > $jumbled_freq[$char])
return false;
return true;
}
/* bradgrafelman: renamed version of Weedpacket's jumble_test() */
function check_valid_guess_rev_3($source_letters, $candidate)
{
if(preg_match("/[^$source_letters]/", $candidate))
{
return false;
}
$source_letters = count_chars($source_letters, 1);
foreach(count_chars($candidate, 1) as $char=>$count)
{
if($count > $source_letters[$char])
{
return false;
}
}
return true;
}
/***********************************
* !!! END OF EDITABLE REGIONS !!! *
***********************************/
/*******************************
* Init stat-keeping variables *
*******************************/
$times = array_fill(0, count($funcs), array());
$medians = array_fill(0, count($params), array());
/*************
* Run tests *
*************/
for($func_idx = 0; $func_idx < count($funcs); $func_idx++)
{
$times[$func_idx] = array_fill(0, count($params), array());
for($param_idx = 0; $param_idx < count($params); $param_idx++)
{
for($i = 0; $i < $num_times; $i++)
{
$start = microtime(true);
call_user_func_array($funcs[$func_idx], $params[$param_idx]);
$end = microtime(true);
$times[$func_idx][$param_idx][] = ($end - $start) * $unit_conv[0];
}
// Sort stored times
sort($times[$func_idx][$param_idx]) or die('error sorting times');
// Store median value
$medians[$param_idx][$func_idx] =
$times[$func_idx][$param_idx][floor($num_times / 2)];
}
// Announce completion of testing for function
if($sound)
echo "\x07";
}
/***********************************
* Generate output of test results *
* (grouped by function) *
***********************************/
echo "Number of executions: $num_times\n\n";
for($func_idx = 0; $func_idx < count($funcs); $func_idx++)
{
echo "Function #$func_idx :\n";
for($param_idx = 0; $param_idx < count($params); $param_idx++)
{
echo "\t$funcs[$func_idx](" . implode(',', $params[$param_idx]) . ")\n";
// Variable rename for brevity
$p = $precision;
printf(
"\t\tMin: %.{$p}f %4\$s\n\t\tMax: %.{$p}f %4\$s\n"
. "\t\tAvg: %.{$p}f %4\$s\n",
$times[$func_idx][$param_idx][0],
$times[$func_idx][$param_idx][$num_times - 1],
(array_sum($times[$func_idx][$param_idx]) / $num_times),
$unit_conv[1]
);
}
}
echo "\n--------------------------------------------------\n\n";
/***********************************
* Generate output of test results *
* (grouped by parameters) *
* (based on func medians) *
***********************************/
for($param_idx = 0; $param_idx < count($params); $param_idx++)
{
echo "Parameter Group #$param_idx (" . implode(',', $params[$param_idx])
. ") :\n";
echo "\tMedians :\n";
// Sort median values
asort($medians[$param_idx]) or die('error sorting medians');;
foreach($medians[$param_idx] as $func_idx => $median)
{
// Variable rename for brevity
$p = $precision;
printf(
"\t\t%s: %.{$p}f %s\n",
$funcs[$func_idx],
$median,
$unit_conv[1]
);
}
}
and the results:
Number of executions: 25000
Function #0 :
check_valid_guess_rev_1(APEC,PEACE)
Min: 0.009775 msec
Max: 0.121832 msec
Avg: 0.011212 msec
check_valid_guess_rev_1(APEC,PACES)
Min: 0.010014 msec
Max: 0.446081 msec
Avg: 0.011878 msec
check_valid_guess_rev_1(TOM MARVOLO RIDDLE,I AM LORD VOLDEMORT)
Min: 0.011921 msec
Max: 0.262976 msec
Avg: 0.013390 msec
Function #1 :
check_valid_guess_rev_2(APEC,PEACE)
Min: 0.043869 msec
Max: 0.850916 msec
Avg: 0.046381 msec
check_valid_guess_rev_2(APEC,PACES)
Min: 0.044823 msec
Max: 0.217199 msec
Avg: 0.046985 msec
check_valid_guess_rev_2(TOM MARVOLO RIDDLE,I AM LORD VOLDEMORT)
Min: 0.044823 msec
Max: 0.602007 msec
Avg: 0.047439 msec
Function #2 :
check_valid_guess_rev_3(APEC,PEACE)
Min: 0.013828 msec
Max: 0.666142 msec
Avg: 0.015597 msec
check_valid_guess_rev_3(APEC,PACES)
Min: 0.007868 msec
Max: 0.097036 msec
Avg: 0.009406 msec
check_valid_guess_rev_3(TOM MARVOLO RIDDLE,I AM LORD VOLDEMORT)
Min: 0.016928 msec
Max: 0.356197 msec
Avg: 0.018463 msec
--------------------------------------------------
Parameter Group #0 (APEC,PEACE) :
Medians :
check_valid_guess_rev_1: 0.010967 msec
check_valid_guess_rev_3: 0.015020 msec
check_valid_guess_rev_2: 0.046015 msec
Parameter Group #1 (APEC,PACES) :
Medians :
check_valid_guess_rev_3: 0.009060 msec
check_valid_guess_rev_1: 0.011921 msec
check_valid_guess_rev_2: 0.046968 msec
Parameter Group #2 (TOM MARVOLO RIDDLE,I AM LORD VOLDEMORT) :
Medians :
check_valid_guess_rev_1: 0.013113 msec
check_valid_guess_rev_3: 0.017881 msec
check_valid_guess_rev_2: 0.046968 msec
@: It would appear your suspicions were correct; your function (rev_3) beat my faster function (rev_1) in group #1 where an invalid character was used.
EDIT: ... and I'm stupid. Forgot that the whole point of your use of the regexp was such that the count_chars() was only done for guessed strings that didn't contain any invalid letters. Oopsie.
Regardless, removing the isset() only affected the function's median time for param group #2 with the given precision (presumably because it was a longer string and the isset() was called more times).