Last active
August 27, 2020 21:07
-
-
Save drupol/e43dd8e02da56fc3013a4e37ee3749d9 to your computer and use it in GitHub Desktop.
Finding primes in PHP with a lazy collection library.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* @file | |
* Example/demo file. | |
* | |
* @see https://github.com/loophp/collection | |
*/ | |
declare(strict_types=1); | |
include 'vendor/autoload.php'; | |
use loophp\collection\Collection; | |
use function in_array; | |
use const INF; | |
/** | |
* Get the divisor of a given number. | |
* | |
* @param float $num | |
* The number. | |
* @param int $start | |
* The start. | |
* | |
* @return \Traversable | |
* The divisors of the number. | |
*/ | |
function factors(float $num, int $start = 1): Traversable | |
{ | |
if (0 === $num % $start) { | |
yield $start => $start; | |
yield $num / $start => $num / $start; | |
} | |
if (ceil(sqrt($num)) >= $start) { | |
yield from factors($num, $start + 1); | |
} | |
} | |
/** | |
* Check if a number is a multiple of 2. | |
* | |
* @param $value | |
* The number. | |
* | |
* @return bool | |
* Whether or not the number is a multiple of 2. | |
*/ | |
$notMultipleOf2 = static function ($value): bool { | |
return 0 !== $value % 2; | |
}; | |
/** | |
* Check if a number is a multiple of 3. | |
* | |
* @param $value | |
* The number. | |
* | |
* @return bool | |
* Whether or not the number is a multiple of 3. | |
*/ | |
$notMultipleOf3 = static function ($value): bool { | |
$sumIntegers = static function ($value): float { | |
return array_reduce( | |
mb_str_split((string) $value), | |
static function ($carry, $value) { | |
return $value + $carry; | |
}, | |
0 | |
); | |
}; | |
$sum = $sumIntegers($value); | |
while (10 < $sum) { | |
$sum = $sumIntegers($sum); | |
} | |
return 0 !== $sum % 3; | |
}; | |
/** | |
* Check if a number is a multiple of 5. | |
* | |
* @param $value | |
* The number. | |
* | |
* @return bool | |
* Whether or not the number is a multiple of 5. | |
*/ | |
$notMultipleOf5 = static function ($value): bool { | |
return !in_array(mb_substr((string) $value, -1), ['0', '5'], true); | |
}; | |
/** | |
* Check if a number is a multiple of 7. | |
* | |
* @param $value | |
* The number. | |
* | |
* @return bool | |
* Whether or not the number is a multiple of 7. | |
*/ | |
$notMultipleOf7 = static function ($value): bool { | |
$number = $value; | |
while (14 <= $number) { | |
$lastDigit = mb_substr((string) $number, -1); | |
if ('0' === $lastDigit) { | |
return true; | |
} | |
$number = (int) abs((int) mb_substr((string) $number, 0, -1) - 2 * (int) $lastDigit); | |
} | |
return !(0 === $number || 7 === $number); | |
}; | |
/** | |
* Check if a number is a multiple of 11. | |
* | |
* @param $value | |
* The number. | |
* | |
* @return bool | |
* Whether or not the number is a multiple of 11. | |
*/ | |
$notMultipleOf11 = static function ($value): bool { | |
$number = $value; | |
while (11 < $number) { | |
$lastDigit = mb_substr((string) $number, -1); | |
if ('0' === $lastDigit) { | |
return true; | |
} | |
$number = (int) abs((int) mb_substr((string) $number, 0, -1) - (int) $lastDigit); | |
} | |
return !(0 === $number || 11 === $number); | |
}; | |
/** | |
* Check if a number have more than 2 divisors. | |
* | |
* @param $value | |
* The number. | |
* | |
* @return bool | |
* Whether or not the number has more than 2 divisors. | |
*/ | |
$valueHavingMoreThan2Divisors = static function ($value): bool { | |
$i = 0; | |
foreach (factors($value) as $factor) { | |
if (2 < $i++) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
$start = microtime(true); | |
$primes = Collection::range(9, INF, 2) // Count from 10 to infinity | |
->filter($notMultipleOf2) // Filter out multiples of 2 | |
->filter($notMultipleOf3) // Filter out multiples of 3 | |
->filter($notMultipleOf5) // Filter out multiples of 5 | |
->filter($notMultipleOf7) // Filter out multiples of 7 | |
->filter($notMultipleOf11) // Filter out multiples of 11 | |
->filter($valueHavingMoreThan2Divisors) // Filter out values having more than 2 divisors. | |
->prepend(2, 3, 5, 7) // Add back digits that were removed | |
->normalize() // Re-index the keys | |
->limit(100); // Take the 100 first prime numbers. | |
print_r($primes->all()); | |
$time = microtime(true) - $start; | |
var_dump($time); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment