php实现的笛卡儿积

  之前在网上找到一个大牛写的版本(网址已经记不得了。。),如下

  

 1 function Descartes1() 
 2     {  //Cartesian product of arrays or strings or something else except empty array
 3        //note that when there is only one argent, it must be an array with more than one elements, otherwise it will result in an warning and wrong result
 4       $t = func_get_args(); 
 5 
 6       if(func_num_args() == 1) return call_user_func_array( __FUNCTION__, $t[0] );
 7 
 8       $a = array_shift($t); 
 9 
10       if(! is_array($a)) $a = array($a);
11 
12       $a = array_chunk($a, 1); 
13 
14       do {  
15         $r = array();  
16         $b = array_shift($t);  
17         if(! is_array($b)) $b = array($b);
18 
19         foreach($a as $p)  
20             foreach(array_chunk($b, 1) as $q)  
21                 $r[] = array_merge($p, $q);
22 
23         $a = $r;
24 
25       }while($t); 
26 
27       return $r;  
28     }
Descartes1

 

  在实际使用过程中,若输入的 数组过大,则会导致内存不够用,于是 就将其改为了 yield 版本,如下:

 1     function Descartes()
 2     {
 3         $args = func_get_args();
 4         if (func_num_args() == 1 && is_array($args[0])) $args=$args[0];
 5   
 6             $i = 0;
 7             $args_len = [];
 8 
 9             while ($i < count($args)){//modify each argument to array
10                 $args_len[] = is_array($args[$i]) ? ( count($args[$i++]) - 1 ) : (int) ( ($args[$i] = array($args[$i])) && ++$i ) - 1;
11                 #$args_len[] = is_array($args[$i]) ? count($args[$i])-1 : 0;
12                 #$i++;
13             }
14 
15             foreach(Descartes_yield($args_len, $args) as $e){
16                 yield $e;
17             }
18     }
19 20     function Descartes_yield($arr_len, $arr_data)
21     {
22         $len = count($arr_len);
23         $temp_arr = array_pad(array(), $len, 0);
24         $temp_arr[0]--;
25         
26         while($temp_arr != $arr_len) {
27             $temp_arr[0]++;
28 
29             $i = 0;
30             $result = [];
31 
32             while ($i < $len) {
33                 if ($temp_arr[$i] > $arr_len[$i]) {
34                     $temp_arr[$i] = 0;
35                     $temp_arr[$i+1]++;
36                 }
37                 $i++;
38             }
39             $i=0;
40             while($i < $len) {
41                 $result[$i] = $arr_data[$i][$temp_arr[$i]];
42                 $i++;
43             }
44 
45             yield $result;
46         }    
47     }

  下面是测试代码:

#Descartes(array(1,2),["a","b"],3);
 # 测试代码:
 # foreach (
Descartes( array(1,2), ["a","b"], 3) as $descar )
 #  print_r( $descar );

  不知道 速度 会不会比之前的慢,不过至少在 大量数据 做笛卡儿积的时候,可以跑起来了~

  又看到一个写的特别棒的,原文网址https://skyverd.com/php_array_function_cartesian/,如下:

 1 $arr = array(
 2     array("a","b"),
 3     range(1,100),
 4     array("A","B","C")
 5 );
 6
7
8
9 fun($arr); 10 print_r($res); 11 12 function fun($arr, $tmp = array()) 13 { 14 foreach(array_shift($arr) as $v) 15 { 16 $tmp[] = $v; 17 if($arr) 18 { 19 fun($arr, $tmp); 20 } 21 else 22 { 23 $GLOBALS["res"][] = implode(",", $tmp); 24 25 } 26 array_pop($tmp); 27 } 28 }

简单的测试了一下:

//memory_limit = 512M, 64位
range(1,10000000);//7个零,只有该数组时,php直接报错

$arr = array(
    array("a","b"),
    range(1,100000), // 5个零
    array("A","B","C")
);//三个版本都正常运行



$arr1 = array(
    array("a","b"),
    range(1,1000000), // 6个零
    array("A","B","C")
);//版本1,3直接报错,内存不够,版本2运行良好

 

posted on 2016-10-17 14:34  lc_D_a  阅读(230)  评论(0编辑  收藏  举报

导航