У меня есть каталог изображений, который может содержать от 100 до многих тысяч изображений. Мне нужно взять образец 81 случайного изображения из этого каталога для использования (в массиве).
В настоящее время я использую следующее, чтобы получить изображение
$locations = 'compressed/';
$images = glob($locations . '*', GLOB_BRACE);
$selected = $images[array_rand($images)];
Проблема этого метода заключается в том, что возможно получить одно и то же изображение дважды (хотя и редко в больших выборках).
Я также видел, что можно использовать opendir, затем перетасовывать массив. Может кто-нибудь сказать, пожалуйста, какой из них эффективнее использовать? Я бы предположил, что использование shuffle с захватом первых 81 элементов было бы лучше, но медленнее для больших количеств (поскольку перетасовка больших массивов заняла бы больше времени).
Любые предложения по сложности времени моей текущей настройки, в отличие от использования opendir (или других методов, которые я, возможно, не знаю)?
Спасибо
Это действительно хороший вопрос, я бы хотел, чтобы больше таких вопросов появилось.
$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 что довольно быстро.
Обратите внимание на логическую ловушку, которую я не принял во внимание:
for
цикл будет работать вечно.Последнее замечание: я абсолютно уверен, что кто-то умнее меня может придумать что-то лучше, но пока это будет работать.
Кроме того, поскольку я использую PHP 7.x, у меня есть преимущество opcache и производительность будет лучше с моей стороны, ваши результаты могут отличаться.
Обратите внимание, что если количество файлов очень мало, for
Цикл будет работать дольше, так как изменение столкновения выше на меньших выборках.
Других решений пока нет …