Php 多维数组中的数组置换保留键
这两天来,我一直在疯狂地试图实现这一目标,也许你能启发我。这是一个马投注排列。每次用户播放时,我都会得到一个多维数组(2级)。第一级包含比赛ID,第二级包含用户为该比赛选择的马。看起来是这样的:Php 多维数组中的数组置换保留键,php,recursion,multidimensional-array,permutation,combinations,Php,Recursion,Multidimensional Array,Permutation,Combinations,这两天来,我一直在疯狂地试图实现这一目标,也许你能启发我。这是一个马投注排列。每次用户播放时,我都会得到一个多维数组(2级)。第一级包含比赛ID,第二级包含用户为该比赛选择的马。看起来是这样的: $play = array ( '4' => array(7, 32), '8' => array(4), '2' => array(9), '12' => array('5'), '83' => array('10', '11',
$play = array
(
'4' => array(7, 32),
'8' => array(4),
'2' => array(9),
'12' => array('5'),
'83' => array('10', '11', '12', ''),
'9' => array('3'),
);
Array
(
[0] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 10
[5] => 3
)
[1] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 11
[5] => 3
)
[2] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 12
[5] => 3
)
[3] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 10
[5] => 3
)
[4] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 11
[5] => 3
)
[5] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 12
[5] => 3
)
)
我需要知道那出戏所有可能的组合是什么。使用此功能可以轻松完成以下操作:
function permutations(array $array)
{
switch (count($array)) {
case 1:
return $array[0];
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
$a = array_shift($array);
$b = permutations($array);
$return = array();
foreach ($a as $key => $v) {
if(is_numeric($v))
{
foreach ($b as $key2 => $v2) {
$return[] = array_merge(array($v), (array) $v2);
}
}
}
return $return;
}
这将返回一个包含所有可能组合的数组。到目前为止还不错,结果如下:
$play = array
(
'4' => array(7, 32),
'8' => array(4),
'2' => array(9),
'12' => array('5'),
'83' => array('10', '11', '12', ''),
'9' => array('3'),
);
Array
(
[0] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 10
[5] => 3
)
[1] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 11
[5] => 3
)
[2] => Array
(
[0] => 7
[1] => 4
[2] => 9
[3] => 5
[4] => 12
[5] => 3
)
[3] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 10
[5] => 3
)
[4] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 11
[5] => 3
)
[5] => Array
(
[0] => 32
[1] => 4
[2] => 9
[3] => 5
[4] => 12
[5] => 3
)
)
我的问题:我需要每匹马的数组“密钥”是“比赛ID”,而不是0,1,2,3我需要这样的结果:
Array
(
[0] => Array
(
[4] => 7
[8] => 4
[2] => 9
[12] => 5
[83] => 10
[9] => 3
)
[1] => Array
(
[4] => 7
[8] => 4
[2] => 9
[12] => 5
[83] => 11
[9] => 3
)
[2] => Array
(
[4] => 7
[8] => 4
[2] => 9
[12] => 5
[83] => 12
[9] => 3
)
[3] => Array
(
[4] => 32
[8] => 4
[2] => 9
[12] => 5
[83] => 10
[9] => 3
)
[4] => Array
(
[4] => 32
[8] => 4
[2] => 9
[12] => 5
[83] => 11
[9] => 3
)
[5] => Array
(
[4] => 32
[8] => 4
[2] => 9
[12] => 5
[83] => 12
[9] => 3
)
)
我怎样才能做到这一点?我知道这是一篇很长的文章,但我需要把它画出来。我在处理函数递归时遇到了一些问题,我完全迷失在每个循环中。以下是您需要的。我已作出必要的评论:
function permutations(array $array)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array;
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array);
$return = array();
foreach ($a as $v) {
if(is_numeric($v))
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
顺便说一句,递归地计算所有排列是很简单的,但是您可能不想在生产环境中这样做。你一定要考虑一个明智的检查,计算有多少排列,如果不超过某个极限,就不允许继续处理。 < P>这就是你需要的。我已作出必要的评论:
function permutations(array $array)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array;
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array);
$return = array();
foreach ($a as $v) {
if(is_numeric($v))
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
顺便说一句,递归地计算所有排列是很简单的,但是您可能不想在生产环境中这样做。你一定要考虑一个明智的检查,计算有多少排列,如果不超过某个极限,就不允许处理继续下去。< P>我把乔恩算法与我最初的算法结合起来,改进了他的函数。我所做的是检查函数是否正在执行递归,如果是,我使用原始数组_merge()(正在工作),否则我使用Jon的数组_combine()(保留数组键) 我认为Jon的答案是正确的,因为他提出了一个巧妙的解决方案来保持数组键完好无损
function permutations(array $array, $inb=false)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array[0];
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array, 'recursing');
$return = array();
foreach ($a as $v) {
if(is_numeric($v))
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
if($inb == 'recursing')
$return[] = array_merge(array($v), (array) $v2);
else
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
我将Jon的算法与我最初使用的算法合并,从而改进了Jon的函数。我所做的是检查函数是否正在执行递归,如果是,我使用原始数组_merge()(正在工作),否则我使用Jon的数组_combine()(保留数组键) 我认为Jon的答案是正确的,因为他提出了一个巧妙的解决方案来保持数组键完好无损
function permutations(array $array, $inb=false)
{
switch (count($array)) {
case 1:
// Return the array as-is; returning the first item
// of the array was confusing and unnecessary
return $array[0];
break;
case 0:
throw new InvalidArgumentException('Requires at least one array');
break;
}
// We 'll need these, as array_shift destroys them
$keys = array_keys($array);
$a = array_shift($array);
$k = array_shift($keys); // Get the key that $a had
$b = permutations($array, 'recursing');
$return = array();
foreach ($a as $v) {
if(is_numeric($v))
{
foreach ($b as $v2) {
// array($k => $v) re-associates $v (each item in $a)
// with the key that $a originally had
// array_combine re-associates each item in $v2 with
// the corresponding key it had in the original array
// Also, using operator+ instead of array_merge
// allows us to not lose the keys once more
if($inb == 'recursing')
$return[] = array_merge(array($v), (array) $v2);
else
$return[] = array($k => $v) + array_combine($keys, $v2);
}
}
}
return $return;
}
我也有同样的问题,丹尼的解决方案对我不好。 我管理数千个排列,并将它们存储在内存中,这是非常昂贵的 以下是我的解决方案:
/**
* Calculate permutation of multidimensional array. Without recursion!
* Ex.
* $array = array(
* key => array(value, value),
* key => array(value, value, value),
* key => array(value, value),
* );
*
* @copyright Copyright (c) 2011, Matteo Baggio
* @param array $anArray Multidimensional array
* @param function $isValidCallback User function called to verify the permutation. function($permutationIndex, $permutationArray)
* @return mixed Return valid permutation count in save memory configuration, otherwise it return an Array of all permutations
*/
function permutationOfMultidimensionalArray(array $anArray, $isValidCallback = false) {
// Quick exit
if (empty($anArray))
return 0;
// Amount of possible permutations: count(a[0]) * count(a[1]) * ... * count(a[N])
$permutationCount = 1;
// Store informations about every column of matrix: count and cumulativeCount
$matrixInfo = array();
$cumulativeCount = 1;
foreach($anArray as $aColumn) {
$columnCount = count($aColumn);
$permutationCount *= $columnCount;
// this save a lot of time!
$matrixInfo[] = array(
'count' => $columnCount,
'cumulativeCount' => $cumulativeCount
);
$cumulativeCount *= $columnCount;
}
// Save the array keys
$arrayKeys = array_keys($anArray);
// It needs numeric index to work
$matrix = array_values($anArray);
// Number of column
$columnCount = count($matrix);
// Number of valid permutation
$validPermutationCount = 0;
// Contain all permutations
$permutations = array();
// Iterate through all permutation numbers
for ($currentPermutation = 0; $currentPermutation < $permutationCount; $currentPermutation++) {
for ($currentColumnIndex = 0; $currentColumnIndex < $columnCount; $currentColumnIndex++) {
// Here the magic!
// I = int(P / (Count(c[K-1]) * ... * Count(c[0]))) % Count(c[K])
// where:
// I: the current column index
// P: the current permutation number
// c[]: array of the current column
// K: number of the current column
$index = intval($currentPermutation / $matrixInfo[$currentColumnIndex]['cumulativeCount']) % $matrixInfo[$currentColumnIndex]['count'];
// Save column into current permutation
$permutations[$currentPermutation][$currentColumnIndex] = $matrix[$currentColumnIndex][$index];
}
// Restore array keys
$permutations[$currentPermutation] = array_combine($arrayKeys, $permutations[$currentPermutation]);
// Callback validate
if ($isValidCallback !== false) {
if ($isValidCallback($currentPermutation, $permutations[$currentPermutation]))
$validPermutationCount++;
// *** Uncomment this lines if you want that this function return all
// permutations
//else
// unset($permutations[$currentPermutation]);
}
else {
$validPermutationCount++;
}
// Save memory!!
// Use $isValidCallback to check permutation, store into DB, etc..
// *** Comment this line if you want that function return all
// permutation. Memory warning!!
unset($permutations[$currentPermutation]);
}
if (!empty($permutations))
return $permutations;
else
return $validPermutationCount;
}
//
// How to?
//
$play = array(
'4' => array(7, 32),
'8' => array(4),
'2' => array(9),
'12' => array('5'),
'83' => array('10', '11', '12', ''), // <-- It accept all values, nested array too
'9' => array('3'),
);
$start = microtime(true);
// Anonymous function work with PHP 5.3.0
$validPermutationsCount = permutationOfMultidimensionalArray($play, function($permutationIndex, $permutationArray){
// Here you can validate the permutation, print it, etc...
// Using callback you can save memory and improve performance.
// You don't need to cicle over all permutation after generation.
printf('<p><strong>%d</strong>: %s</p>', $permutationIndex, implode(', ', $permutationArray));
return true; // in this case always true
});
$stop = microtime(true) - $start;
printf('<hr /><p><strong>Performance for %d permutations</strong><br />
Execution time: %f sec<br/>
Memory usage: %d Kb</p>',
$validPermutationsCount,
$stop,
memory_get_peak_usage(true) / 1024);
/**
*计算多维数组的置换。没有递归!
*前。
*$array=array(
*键=>数组(值,值),
*key=>array(值、值、值),
*键=>数组(值,值),
* );
*
*@版权所有(c)2011,Matteo Baggio
*@param数组$anArray多维数组
*@param function$isValidCallback用户函数被调用以验证排列。函数($permutationIndex,$permutationArray)
*@return mixed返回保存内存配置中的有效置换计数,否则返回所有置换的数组
*/
多维数组的函数置换(数组$anArray,$isValidCallback=false){
//快速退出
如果(空($anArray))
返回0;
//可能的置换量:计数(a[0])*计数(a[1])*…*计数(a[N])
$permutationCount=1;
//存储有关矩阵每列的信息:count和cumulativeCount
$matrixInfo=array();
$cumulativeCount=1;
foreach($a列为$a列){
$columnCount=计数($aColumn);
$permutationCount*=$columnCount;
//这节省了很多时间!
$matrixInfo[]=数组(
“count”=>$columnCount,
'cumulativeCount'=>$cumulativeCount
);
$cumulativeCount*=$columnCount;
}
//保存数组键
$arrayKeys=array\u键($anArray);
//它需要数字索引才能工作
$matrix=数组值($anArray);
//列数
$columnCount=计数($matrix);
//有效置换数
$validPermutationCount=0;
//包含所有排列
$permutations=array();
//遍历所有置换数
对于($currentPermutation=0;$currentPermutation<$permutationCount;$currentPermutation++){
对于($currentColumnIndex=0;$currentColumnIndex<$columnCount;$currentColumnIndex++){
//这是魔术!
//I=int(P/(计数(c[K-1])*…*计数(c[0]))%Count(c[K]))
//其中:
//I:当前列索引
//P:当前排列数
//c[]:当前列的数组
//K:当前列的编号
$index=intval($currentPermutation/$matrixInfo[$currentColumnIndex]['cumulativeCount'])%$matrixInfo[$currentColumnIndex]['count'];
//将列保存到当前排列中
$permutations[$currentPermutation][$currentColumnIndex]=$matrix[$currentColumnIndex][$index];
}
//还原数组键
$permutations[$currentPermutation]=array_combine($arrayKeys,$permutations[$currentPermutation]);
//回调验证
如果($isValidCallback!==false){
if($isValidCallback($currentPermutation,$permutations[$currentPermutation]))
$validPermutationCount++;
//***如果希望此函数返回所有
//排列
//否则
//未设置($permutations[$currentPermutation]);
}
否则{
$validPermutationCount++;
}
//节省内存!!
//使用$isValidCallback检查排列、存储到数据库中等。。
//***如有必要,请评论此行