2010-08-15 37 views
5

Đây là câu hỏi đầu tiên của tôi ở đây :)Cách tạo kết hợp các phần tử trong một số mảng?

Tôi có một mảng với một số trẻ em mảng, mỗi giá trị duy nhất và muốn nhận được tất cả các kết hợp độc đáo của các giá trị đó.

Số lượng mảng được biết nhưng có thể thay đổi theo thời gian.

Ví dụ,

array(
    [0] => array([0]=>'blue',[1]=>'red'), 
    [1] => array([0]=>'sunny',[1]=>'cloudy'), 
    [2] => array([0]=>'sweet',[1]=>'acid'); 

Tôi nên làm gì để có được:

array(
    [0] => array([0]=>'blue',[1]=>'sunny',[2]=>'sweet'), 
    [1] => array([0]=>'blue',[1]=>'sunny',[2]=>'acid'), 
    [2] => array([0]=>'blue',[1]=>'cloudy',[2]=>'sweet'), 
    [3] => array([0]=>'blue',[1]=>'cloudy',[2]=>'acid'), 
    [4] => array([0]=>'red',[1]=>'sunny',[2]=>'sweet'), 
    [5] => array([0]=>'red',[1]=>'sunny',[2]=>'acid'), 
    [6] => array([0]=>'red',[1]=>'cloudy',[2]=>'sweet'), 
    [7] => array([0]=>'red',[1]=>'cloudy',[2]=>'acid')); 

tôi đã cố gắng làm việc đó với vòng lồng nhau nhưng logic của tôi không phải là quá mạnh.

Rất nhiều đánh giá cao nếu ai đó có thể làm sáng tỏ

+0

Bạn luôn có ma trận hình chữ nhật? – NullUserException

+0

Của tôi xấu, kích thước mảng thay đổi khá nhiều thực sự. – Fer

Trả lời

8

(Note: cần một sửa đổi nhỏ để sử dụng trong PHP < 5,3)

Làm điều này (example trên một thông dịch viên trực tuyến):

$f = function() { return func_get_args(); }; 
$res = array_outer($f, 
    array("blue", "red"), 
    array("sunny", "cloudy"), 
    array("sweet", "acid")); 

Chức năng array_outer, lấy cảm hứng từ Mathematica Outer, là:

/** 
* A generalization of the outer product, forming all the possible 
* combinations of the elements of any number of arrays and feeding 
* them to $f. 
* The keys are disregarded 
**/ 
function array_outer($f, array $array1) { 
    $res = array(); 
    $arrays = func_get_args(); 
    array_shift($arrays); 
    foreach ($arrays as $a) { 
     if (empty($a)) 
      return $res; 
    } 

    $num_arrays = count($arrays); 
    $pos = array_fill(0, $num_arrays, 0); 
    while (true) { 
     $cur = array(); 
     for ($i = 0; $i < $num_arrays; $i++) { 
      $cur[] = $arrays[$i][$pos[$i]]; 
     } 
     $res[] = call_user_func_array($f, $cur); 
     for ($i = $num_arrays-1; $i >= 0; $i--) { 
      if ($pos[$i] < count($arrays[$i]) - 1) { 
       $pos[$i]++; 
       break; 
      } else { 
       if ($i == 0) 
        break 2; 
       $pos[$i] = 0; 
      } 
     } 
    } 
    return $res; 
} 
+1

+1 Apesar dos pesares;) – NullUserException

+0

Tôi cúi đầu xấu hổ nhưng để lại câu trả lời làm ví dụ về giải pháp nhanh và bẩn;) – Nicolas78

+0

@Null Đừng lo lắng, vì bạn đã xóa câu trả lời, downvote sẽ biến mất việc tính toán lại đại diện tiếp theo: p – Artefacto

0

latenight giả:

result = [] 
counter = 0 
for i in length(array[0]): 
    for j in length(array[1]): 
    for k in length(array[2]):  
     result[counter] = aray(0: array[0][i], 1: array[1][j], 2: array[2][k]) 
     counter+=1 

mặc dù một điểm mạnh có thể được thực hiện cho một cách tiếp cận đệ quy nếu số lượng mảng đang xảy ra để có được lớn hơn hoặc có thể thay đổi động

+0

@ nicolas78 Cảm ơn bạn đã nhập. Ban đầu tôi đã đi cho một cách tiếp cận tương tự, nhưng có thể có hàng chục mảng để nó trở nên nhanh chóng không thể quản lý được. Chúc mừng! – Fer

4

Dưới đây là một cách tiếp cận đệ quy để này:

$arr = array(
      0 => array(0 =>'blue', 1 =>'red'), 
      1 => array(0 =>'sunny', 1 =>'cloudy'), 
      2 => array(0 =>'sweet', 1 =>'acid') 
     ); 

$combinations = array(); 
getArrayCombinations($arr, $combinations); 
echo '<pre>';print_r($combinations); 

/** 
* Creates an array with all possible combinations 
* @param array main_array - Array to find all the possible combinations of 
* @param array combinations - Array to store the resulting array in 
* @param array batch 
* @param int index 
*/ 
function getArrayCombinations($main_array, &$combinations, $batch=array(), $index=0) 
{ 
    if ($index >= count($main_array)) 
     array_push($combinations, $batch); 
    else 
     foreach ($main_array[$index] as $element) 
     { 
      $temp_array = $batch; array_push($temp_array, $element); 
      getArrayCombinations($main_array, $combinations, $temp_array, $index+1); 
     } 
} 
+0

Giải pháp của bạn cũng hoạt động tốt. Cảm ơn rất nhiều vì sự giúp đỡ và thời gian của bạn – Fer

2

Điều bạn đang thực sự tìm kiếm là một cách để lặp lại chuỗi:

000 
001 
010 
011 
100 
101 
110 
111 

Sẽ tốt hơn nếu chúng tôi không phải giả định rằng kích thước của mỗi mảng đầu vào giống nhau. Vì vậy, nếu chúng ta giảm kích thước của mảng thứ hai bởi 1:

array(
    [0] => array([0]=>'blue',[1]=>'red'), 
    [1] => array([0]=>'sunny'), 
    [2] => array([0]=>'sweet',[1]=>'acid'); 

... chúng ta muốn giá trị tối đa cho cột đó để giảm 1:

000 
001 
100 
101 

trừu tượng này làm cho vấn đề dễ dàng hơn để nghĩ về. Làm thế nào bạn sẽ lặp lại chuỗi này? Trên mỗi lần lặp, bạn tăng cột ngoài cùng bên phải bằng 1. Nếu làm như vậy sẽ tăng nó vượt quá mức tối đa, đặt lại 0 và di chuyển sang trái một cột. Bây giờ bạn lặp lại những gì bạn vừa làm trên cột cuối cùng. Nếu bạn không thể tăng cột này, hãy đặt lại thành 0, di chuyển sang trái, rửa sạch và lặp lại. Nếu bạn di chuyển tất cả các cách trên và đã không thể tăng bất kỳ cột mà không vượt quá tối đa của nó, bạn đã hoàn tất.

Chúng ta có thể quấn logic trên trong một iterator PHP:

class Sequence implements Iterator { 

    private $input; 

    private $hasNext; 
    private $positions; 

    public function __construct(array $input) { 
     $this->input = $input; 
    } 

    public function rewind() { 
     $this->hasNext = true; 
     $this->positions = array(); 
     for ($i = 0; $i < count($this->input); $i++) { 
      $this->positions[$i] = 0; 
     } 
    } 

    public function valid() { 
     return $this->hasNext; 
    } 

    public function current() { 
     $current = array(); 
     for ($i = 0; $i < count($this->positions); $i++) { 
      $current[] = $this->input[$i][$this->positions[$i]]; 
     } 
     return $current; 
    } 

    public function key() {} 

    public function next() { 
     for ($i = count($this->positions) - 1; $i >= 0; $i--) { 
      if ($this->positions[$i] < count($this->input[$i]) - 1) { 
       $this->positions[$i]++; 
       break; 
      } else { 
       $this->positions[$i] = 0; 
       $this->hasNext = $i !== 0; 
      } 
     } 
    } 

} 

next() là việc thực hiện logic trên. reset() chỉ cần đặt từng cột trở về 0 và current() sử dụng trình tự hiện tại làm chỉ mục của đầu vào để trả về giá trị hiện tại.

Đây là nó trong hành động (với "mây" xóa để hiển thị tổng quát của giải pháp):

$input = array(
    array('blue', 'red'), 
    array('sunny'), 
    array('sweet', 'acid') 
); 

$lst = new Sequence($input); 
foreach ($lst as $elt) { 
    print(implode(', ', $elt) . "\n"); 
} 

Và sản lượng của nó:

blue, sunny, sweet 
blue, sunny, acid 
red, sunny, sweet 
red, sunny, acid 
+0

Giải pháp của bạn cũng rất hợp lệ. Cảm ơn nhiều! – Fer

2

giải pháp Rất đơn giản:

$arr = array(
    array('a', 'b', 'c'), 
    array('x', 'y', 'z'), 
    array('1', '2') 
); 

$result = array(); 
foreach ($arr as $a) { 
    if (empty($result)) { 
     $result = $a; 
     continue; 
    } 

    $res = array(); 
    foreach ($result as $r) { 
     foreach ($a as $v) { 
      $res[] = array_merge((array)$r, (array)$v); 
     } 
    } 

    $result = $res; 
} 

var_dump($result); 
+0

Cảm ơn giải pháp này. Tôi tin rằng giải pháp này nhanh hơn giải pháp trên. – machineaddict

Các vấn đề liên quan