Last active
May 26, 2017 18:36
-
-
Save thecrypticace/9634c353c003947960145efcccbc810c to your computer and use it in GitHub Desktop.
PHP Bug
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 | |
class Combinations | |
{ | |
public static function unique($values, $minLength = 1, $maxLength = null) | |
{ | |
// $combinations is an array of [["a"], ["a"], … ["a", "b"], ["a", "b", "c"], …] | |
// The array may not be sorted. Each internal array IS sorted. | |
// Keys produced by the generator are sequential but shouldn't matter | |
$combinations = static::sorted($values, $minLength, $maxLength); | |
// Uncomment this and everything works correctly | |
// $combinations = static::ensurePackedArrays($combinations); | |
$combinations = iterator_to_array($combinations, false); | |
// Uncommenting this changes the results; Still not perfect | |
// sort($combinations, SORT_REGULAR); | |
for ($i=0; $i < 10; $i++) { | |
$combinations = array_unique($combinations, SORT_REGULAR); | |
} | |
// Without packed arrays: | |
// 340 items - using $i < 0; 144 items - using $i < 1 | |
// 62 items - using $i < 2; 36 items - using $i < 10 | |
yield from $combinations; | |
} | |
private static function ensurePackedArrays($values) | |
{ | |
foreach ($values as $value) { | |
$result = []; | |
foreach ($value as $i) { | |
$result[] = $i; | |
} | |
yield $result; | |
} | |
} | |
private static function sorted($values, $minLength = 1, $maxLength = null) | |
{ | |
foreach (static::compute($values, $minLength, $maxLength) as $combo) { | |
sort($combo, SORT_REGULAR); | |
yield array_unique($combo, SORT_REGULAR); | |
} | |
} | |
public static function compute($values, $minLength = 1, $maxLength = null) | |
{ | |
$maxLength = $maxLength ?? count($values); | |
for ($length = $minLength; $length <= $maxLength; $length++) { | |
yield from static::combinations($values, $length); | |
} | |
} | |
private static function combinations($values, $count) | |
{ | |
$numberOfValues = count($values); | |
$possibilities = pow($numberOfValues, $count); | |
for ($i = 0; $i < $possibilities; $i++) { | |
yield iterator_to_array(static::combination($values, $count, $i), false); | |
} | |
} | |
private static function combination($values, $count, $index) | |
{ | |
$numberOfValues = count($values); | |
for ($i = 0; $i < $count; $i++) { | |
// Figure out where in the array to start from, | |
// given the external state and the internal loop state | |
$pos = $index % $numberOfValues; | |
// Supply the next item in the combination | |
yield $values[$pos]; | |
$index = ($index - $pos) / $numberOfValues; | |
} | |
} | |
} |
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 | |
// This should produce 15 items. It doesn't. Change the number of iterations of array_unique to see differences. | |
print_r(iterator_to_array( | |
Combinations::unique(["a", "b", "c", "d"]), | |
false | |
)); |
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 7.1.5-1+deb.sury.org~xenial+2 (cli) (built: May 22 2017 12:48:42) ( NTS ) | |
Copyright (c) 1997-2017 The PHP Group | |
Zend Engine v3.1.0, Copyright (c) 1998-2017 Zend Technologies | |
with Zend OPcache v7.1.5-1+deb.sury.org~xenial+2, Copyright (c) 1999-2017, by Zend Technologies | |
with blackfire v1.17.0~linux-x64-non_zts71, https://blackfire.io, by Blackfireio Inc. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment