Skip to content

Instantly share code, notes, and snippets.

@ostrolucky
Created October 20, 2017 22:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ostrolucky/2947154fae206e876b6c5e1abed0a25e to your computer and use it in GitHub Desktop.
Save ostrolucky/2947154fae206e876b6c5e1abed0a25e to your computer and use it in GitHub Desktop.
Array flatten algorithms benchmark
<?php
$array = [1, 2, 3, 4, [], [5, 6], 7, 8, [9], [10, [11, 12], 13, [14, 15, 16, [17, [18, [19, 20, 21]]]]], 22, 23, 24, [25], 26, [27, [28], [29, [30, 31], [32], [33, [34, [35, 36], 37, 38, [39, 40]]]]]];
function laravel_flatten($array, $depth = INF)
{
return array_reduce($array, function ($result, $item) use ($depth) {
if (! is_array($item)) {
return array_merge($result, [$item]);
} elseif ($depth === 1) {
return array_merge($result, array_values($item));
} else {
return array_merge($result, laravel_flatten($item, $depth - 1));
}
}, []);
}
function knapsack_flatten($collection, $levelsToFlatten = -1)
{
$generatorFactory = function () use ($collection, $levelsToFlatten) {
$flattenNextLevel = $levelsToFlatten < 0 || $levelsToFlatten > 0;
$childLevelsToFlatten = $levelsToFlatten > 0 ? $levelsToFlatten - 1 : $levelsToFlatten;
foreach ($collection as $key => $value) {
if ($flattenNextLevel && (is_array($value) || $value instanceof Traversable)) {
foreach (knapsack_flatten($value, $childLevelsToFlatten) as $childKey => $childValue) {
yield $childKey => $childValue;
}
} else {
yield $key => $value;
}
}
};
$collection = $generatorFactory();
$generatorFactory2 = function() use ($collection) {
foreach ($collection as $value) {
yield $value;
}
};
return iterator_to_array($generatorFactory2());
}
$tests = [
'lstrojny/functional-php' => function ($array) {
$stack = [$array];
$result = [];
while (!empty($stack)) {
$item = array_shift($stack);
if (is_array($item)) {
foreach ($item as $element) {
array_unshift($stack, $element);
}
} else {
array_unshift($result, $item);
}
}
return $result;
},
'laravel collections' => 'laravel_flatten',
'dusank/knapsack' => 'knapsack_flatten',
'recursive_iterator' => function ($array) {
return iterator_to_array(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)), false);
},
'array_walk_recursive' => function ($array) {
$return = array();
array_walk_recursive($array, function($a) use (&$return) { $return[] = $a; });
return $return;
},
];
foreach ($tests as $suite => $closure) {
$time = microtime(true);
for ($i=0;$i<100000;$i++) {
call_user_func($closure, $array);
}
echo $suite.' finished in '.(microtime(true) - $time) . 's'.PHP_EOL;
}
/*
lstrojny/functional-php finished in 3.0966401100159s
laravel collections finished in 2.0682859420776s
dusank/knapsack finished in 4.2100491523743s
recursive_iterator finished in 1.9282908439636s
array_walk_recursive finished in 0.74895691871643s
*/
@qRoC
Copy link

qRoC commented Jun 15, 2018

recursive_iterator is wrong, because it will not work with objects.
Need use SELF_FIRST, or extends RecursiveArrayIterator with override hasChildren.

@ostrolucky
Copy link
Author

This was made for very specific use case, not as general specific solution

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment