Как получить из массива:
$a = [
'color' => ['red', 'blue'],
'size' => ['10-12', '12-14']
];
такой массив
$b = [
['color' => 'red', 'size' => '10-12'],
['color' => 'blue', 'size' => '10-12'],
['color' => 'red', 'size' => '12-14'],
['color' => 'blue', 'size' => '12-14'],
];
ключей и значений может быть любое кол-во,
имена ключей и значений могут быть разные
Нашел такое решение
function addValue(&$arr, $key, $val)
{
if (!count($arr)) {
$arr[] = [$key => $val];
return;
}
foreach($arr as $num => $values) {
$arr[$num][$key] = $val;
}
}
$b = [];
foreach($a as $key => $values) {
$copyB = $b;
$newB = [];
foreach($values as $value) {
$currentB = $copyB;
addValue($currentB, $key, $value);
$newB = array_merge($newB, $currentB);
}
$b = $newB;
}
Исходные данные
$a = [
'color' => ['red', 'blue'],
'size' => ['10-12', '12-14', '15-16'],
// еще элементы
];
генерим структуру для перестановок
foreach(array_keys($a) as $idx => $key){
$data[$idx] = ['key' => $key, 'c' => count($a[$key]), 'v' => 0];
}
где каждый элемент содержит ключ массива $a
, число возможных элементов в нем, и текущее значение в перестановке.
далее в виде рекурсивной процедуры генерация перестановок, на последнем уровне рекурсии пополняем массив рузультатов по текущей перестановке:
function gen(&$data, $s = 0){
if($s == count($data)){
global $a;
global $result;
$v = [];
foreach($data as $x){
$v[$x['key']] = $a[$x['key']][$x['v']];
}
$result[] = $v;
return;
}
for($i=0; $i < $data[$s]['c']; $i++){
$data[$s]['v'] = $i;
gen($data, $s+1);
}
}
запускаем
$result = [];
gen($data);
print_r($result);
результат
Array (
[0] => Array (
[color] => red
[size] => 10-12
)
[1] => Array (
[color] => red
[size] => 12-14
)
[2] => Array (
[color] => red
[size] => 15-16
)
[3] => Array (
[color] => blue
[size] => 10-12
)
[4] => Array (
[color] => blue
[size] => 12-14
)
[5] => Array (
[color] => blue
[size] => 15-16
)
)
пример с другими исходными данными
$a = [
'color' => ['red', 'blue'],
'size' => ['10-12'],
'weight' => ['bold', 'normal'],
];
результат
Array (
[0] => Array (
[color] => red
[size] => 10-12
[weight] => bold
)
[1] => Array (
[color] => red
[size] => 10-12
[weight] => normal
)
[2] => Array (
[color] => blue
[size] => 10-12
[weight] => bold
)
[3] => Array (
[color] => blue
[size] => 10-12
[weight] => normal
)
)
array_map
$array = [
'color' => ['red', 'blue'],
'size' => ['10-12', '12-14']
];
function arrayMapping($a, $b){
return [
"color" => $a,
"size" => $b
];
}
$output_array = array_map("arrayMapping", $array['color'], $array['size']);
/*
Array (
[0] => Array ( [color] => red [size] => 10-12 )
[1] => Array ( [color] => blue [size] => 12-14 )
)
*/
нашел такое решение, как вам
function cartesian($input) {
$result = array();
while (list($key, $values) = each($input)) {
// If a sub-array is empty, it doesn't affect the cartesian product
if (empty($values)) {
continue;
}
// Seeding the product array with the values from the first sub-array
if (empty($result)) {
foreach($values as $value) {
$result[] = array($key => $value);
}
}
else {
// Second and subsequent input sub-arrays work like this:
// 1. In each existing array inside $product, add an item with
// key == $key and value == first item in input sub-array
// 2. Then, for each remaining item in current input sub-array,
// add a copy of each existing array inside $product with
// key == $key and value == first item of input sub-array
// Store all items to be added to $product here; adding them
// inside the foreach will result in an infinite loop
$append = array();
foreach($result as &$product) {
// Do step 1 above. array_shift is not the most efficient, but
// it allows us to iterate over the rest of the items with a
// simple foreach, making the code short and easy to read.
$product[$key] = array_shift($values);
// $product is by reference (that's why the key we added above
// will appear in the end result), so make a copy of it here
$copy = $product;
// Do step 2 above.
foreach($values as $item) {
$copy[$key] = $item;
$append[] = $copy;
}
// Undo the side effecst of array_shift
array_unshift($values, $product[$key]);
}
// Out of the foreach, we can add to $results now
$result = array_merge($result, $append);
}
}
return $result;
}
Уже предложено достаточно решений. Поэтому добавлю свой вариант без рекурсий. Да ещё и на генераторе!
$in = [
'a' => ['11', '12'],
'b' => ['21', '22'],
];
function decart($in)
{
$keys = array_keys($in);
// тут будем хранить индексы подходящих значений
$offset = array_fill_keys($keys, 0);
// стартуем генератор
while (true) {
// собираем очередной набор значений по их индексам
$arr = [];
foreach ($keys as $i => $key) {
$arr[] = $in[$key][$offset[$key]];
}
// и возвращаем набор
yield $arr;
// всегда увеличивем индекс значений первого вложенного массива
$offset[$keys[0]]++;
// если вышли за его границы, то ..
if ($offset[$keys[0]] === count($in[$keys[0]])) {
// .. снова будем перебирать значения с первого, но ..
$offset[$keys[0]] = 0;
// .. увеличиваем индекс следующего массива в котором это возможно
for ($i = 1; $i < count($keys); $i++) {
$offset[$keys[$i]]++;
// удалось и нет переполнения? - можем вернуться в генератор и ждать запроса
if ($offset[$keys[$i]] < count($in[$keys[$i]])) {
break;
}
// в случае переполнения сбрасываем индекс и для этого массива, -
// - очередная итерация увеличит следующий по порядку
$offset[$keys[$i]] = 0;
// кроме случая, когда достигнут конец исходного массива - останавливаем генератор
if ($i === count($keys) - 1) {
break 2;
}
}
}
}
}
$keys = array_keys($in);
$generator = decart($in);
$out = [];
foreach ($generator as $values) {
$out[] = array_combine($keys, $values);
}
var_dump($out);
В итоге имеем декартово произведение значений:
array(4) {
[0]=>array(2) {
["a"]=>string(2) "11"
["b"]=>string(2) "21"
}
[1]=>array(2) {
["a"]=>string(2) "12"
["b"]=>string(2) "21"
}
[2]=>array(2) {
["a"]=>string(2) "11"
["b"]=>string(2) "22"
}
[3]=>array(2) {
["a"]=>string(2) "12"
["b"]=>string(2) "22"
}
}
Задача становится проще, если её разделить на небольшие части. Для начала бывает полезно сформулировать проблему более конкретно. В данном случае можно сказать, что мы хотим получить все возможные комбинации параметров и при этом не потерять их имена. Начнём с комбинаций. Это проще, если комбинировать только два набора значений. Можно написать функцию типа такой:
function arr_comb($a, $b) {
$combs = [];
foreach ($a as $aVal) {
foreach ($b as $bVal) {
$combs[] = [$aVal, $bVal];
}
}
return $combs;
}
Очень просто! Теперь попробуем собрать комбинации трёх наборов значений. А это комбинация третьего с результатами комбинации первых двух. А четырёх? Рекурсия напрашивается сама :-)
function arr_comb(...$arrs) {
$size = count($arrs);
if ($size === 2) {
list($a, $b) = $arrs;
$combs = [];
foreach ($a as $aVal) {
foreach ($b as $bVal) {
$combs[] = [$aVal, $bVal];
}
}
return $combs;
} elseif ($size > 2) {
$last = array_pop($arrs);
return arr_comb(arr_comb(...$arrs), $last);
} else {
return $arrs;
}
}
Однако, мы комбинируем результаты-массивы со значениями и на выходе получаем вложенные массивы. Надо сделать их плоскими, например так:
elseif ($size > 2) {
$last = array_pop($arrs);
$combs = arr_comb(arr_comb(...$arrs), $last);
return array_map(function($combo) {
$flatArr = array_values($combo[0]);
$flatArr[] = $combo[1];
return $flatArr;
}, $combs);
}
В итоге мы получили универсальную функцию комбинирования значений массивов, которая наверняка пригодится и в других задачах. А теперь используем её:
function build($arr) {
$combs = arr_comb(...array_values($arr)); // все комбинации
$keys = array_keys($arr); // имена параметров
return array_map(function($vals) use($keys) {
return array_combine($keys, $vals);
}, $combs);
}
function cross($array)
{
$result = [];
$current = array_splice($array, -1);
foreach ($current as $key => $values) {
foreach ( $values as $value) {
if (empty($array)) {
array_push($result, [$key => $value]);
} else {
foreach (cross($array) as $temp) {
array_push($result, array_merge([$key => $value], $temp));
}
}
}
}
return $result;
}
print_r(cross($a));
так лучше
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
У меня на input весит обработчик с отправкой AJAX на сервер вот такого вида
Почему функция возвращает NULL? Если сделать дамп в функции перед словом return тогда выводится ожидаемый масив, при дампе функции tree_menu() - NULL