сложность времени — PHP OpenDir против array_rand

У меня есть каталог изображений, который может содержать от 100 до многих тысяч изображений. Мне нужно взять образец 81 случайного изображения из этого каталога для использования (в массиве).

В настоящее время я использую следующее, чтобы получить изображение

$locations = 'compressed/';
$images = glob($locations . '*', GLOB_BRACE);
$selected = $images[array_rand($images)];

Проблема этого метода заключается в том, что возможно получить одно и то же изображение дважды (хотя и редко в больших выборках).

Я также видел, что можно использовать opendir, затем перетасовывать массив. Может кто-нибудь сказать, пожалуйста, какой из них эффективнее использовать? Я бы предположил, что использование shuffle с захватом первых 81 элементов было бы лучше, но медленнее для больших количеств (поскольку перетасовка больших массивов заняла бы больше времени).

Любые предложения по сложности времени моей текущей настройки, в отличие от использования opendir (или других методов, которые я, возможно, не знаю)?

Спасибо

3

Решение

Это действительно хороший вопрос, я бы хотел, чтобы больше таких вопросов появилось.


$start = microtime(true);

function recursiveDirectoryIterator($path) {
foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $file) {
if(!$file->isDir()) {
yield $file->getFilename() . $file->getExtension();
}
}
}

$instance = recursiveDirectoryIterator('../vendor');
$files = [];
foreach($instance as $value) {
$files[] = $value;
}

$total_files = count($files);
$random_array = [];
$total_randoms = 81;
for(;;){
$rand = random_int(0, $total_files);
if(count($random_array) == $total_randoms) {
break;
}
if(!isset($random_array[$rand])) {
$random_array[$rand] = $files[$rand];
}
}

echo "Mem peak usage: " . (memory_get_peak_usage(true)/1024/1024)." MiB" . '<br>';
echo "Total number of files: " . $total_files . '<br>';
echo "Completed in: ", microtime(true) - $start, " seconds" . '<br>';
echo '<pre>';
print_r($final);
die;

Выход

Mem peak usage: 2 MiB
Total number of files: 12972
Completed in: 0.74663186073303 seconds
Array
(
[6118] => PreDec.phpphp
[4560] => LabelMaker.phpphp
[10360] => RecursiveDirectoryIterator.phpphp
[4124] => Enum.phpphp
[2671] => ImportCommand.phpphp
[1250] => WebDriverTest.phpphp
[10518] => AutoExpireFlashBagTest.phpphp
[6805] => zsdtPackTask.phpphp
[4288] => HTML.Trusted.txttxt
[6462] => border-disable.phptphpt
[4980] => main.ymlyml
[505] => StepTested.phpphp
[5219] => xhprof.ini.j2j2
[12959] => RequestInterface.phpphp
[1423] => xd5.phpphp
[4285] => HTML.TidyAdd.txttxt
[4930] => .travis.ymlyml
[12013] => Defined.phpphp
[8779] => Markdown.phpphp
[5979] => pt.phpphp
[278] => AbstractAdapter.phpphp
[2155] => SemVerTest.phpphp
[523] => ServicesResolverFactory.phpphp
[11686] => AbstractDumper.phpphp
[7320] => Functions.phpphp
[7763] => mocked_clone.tpl.distdist
[11541] => test_landscape.gifgif
[3557] => RegionSelectorSpec.phpphp
[2600] => RoutingAccessSniff.phpphp
[9496] => LoaderTest.phpphp
[4958] => setup-RedHat.ymlyml
[3477] => api.featurefeature
[7975] => WtfCommand.phpphp
[9001] => ElseIfDeclarationSniff.phpphp
[11696] => VarDumperTestTrait.phpphp
[11211] => empty.ymlyml
[10925] => ObjectRouteLoader.phpphp
[10936] => MatcherDumperInterface.phpphp
[2685] => ConnectCommand.phpphp
[9066] => EmptyStyleDefinitionSniff.phpphp
[3536] => BehatTestExtensionInstallStorage.phpphp
[4720] => ansible-args.mdmd
[326] => ZipOutputParser.phpphp
[9565] => BufferedOutput.phpphp
[712] => CliExtension.phpphp
[3436] => .travis.ymlyml
[4471] => HTMLPurifier.kses.phpphp
[2764] => RouteSubscriberCommand.phpphp
[10633] => RoutableFragmentRenderer.phpphp
[6906] => Reference.phpphp
[11663] => DoctrineCaster.phpphp
[8042] => GitHubChecker.phpphp
[1466] => ImageDriverInterface.phpphp
[2652] => DrupalCommand.phpphp
[7265] => classUsesNamespacedFunction.phpphp
[12129] => ExtensionInterface.phpphp
[12184] => ConditionalExpression.phpphp
[12128] => EscaperExtension.phpphp
[6678] => JsHintTask.phpphp
[5351] => main.ymlyml
[2104] => _bootstrap.phpphp
[143] => deploy_branch
[1360] => x8f.phpphp
[4713] => composer-dependency.mdmd
[7495] => ExceptionInAssertPostConditionsTest.phpphp
[4508] => info.txttxt
[8369] => 6.1.3-curl-adapter.phpphp
[3093] => create-data.ymlyml
[1882] => .gitkeepgitkeep
[3747] => example.makemake
[507] => EventDispatchingBackgroundTester.phpphp
[3336] => shell.ymlyml
[397] => AnnotationReader.phpphp
[4005] => xhUnitTest.phpphp
[5168] => test.ymlyml
[10909] => MissingMandatoryParametersException.phpphp
[8686] => FacetSetTest.phpphp
[2321] => FileCache.phpphp
[10538] => StreamedResponseTest.phpphp
[12572] => in.testtest
[7031] => StringContainsToken.phpphp
)

Код сломан.

я использовал RecursiveDirectoryIterator с Генератор сэкономить на использовании памяти.

Затем, вместо перетасовки огромного массива, я выбрал другой подход: сгенерировать 81 случайное, неповторяющееся число в диапазоне максимального числа массивов файлов и 0. После того, как у вас есть случайные числа, просто используйте array_intersect_key что довольно быстро.

Обратите внимание на логическую ловушку, которую я не принял во внимание:

  • Если общее количество файлов меньше 81, for цикл будет работать вечно.


Последнее замечание: я абсолютно уверен, что кто-то умнее меня может придумать что-то лучше, но пока это будет работать.

Кроме того, поскольку я использую PHP 7.x, у меня есть преимущество opcache и производительность будет лучше с моей стороны, ваши результаты могут отличаться.

Обратите внимание, что если количество файлов очень мало, for Цикл будет работать дольше, так как изменение столкновения выше на меньших выборках.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]