Combinations array into array in PHP - php

I will try to explain everything :)
I have 2 arrays:
$packs = array(
array(
'name' => 'Pack 1',
'zones' => array(
array('zone' => 2),
array('zone' => 2),
)
),
array(
'name' => 'Pack 2',
'zones' => array(
array('zone' => 2),
array('zone' => 2),
array('zone' => 2),
)
),
array(
'name' => 'Pack 3',
'zones' => array(
array('zone' => 2),
array('zone' => 3),
)
),
array(
'name' => 'Pack 4',
'zones' => array(
array('zone' => 3),
array('zone' => 3),
)
)
);And products:
$products = array(
array(
'id' => '1',
'zone' => '2'
),
array(
'id' => '8',
'zone' => '2'
),
array(
'id' => '13',
'zone' => '3'
),
array(
'id' => '11',
'zone' => '2'
),
array(
'id' => '10',
'zone' => '2'
),
array(
'id' => '12',
'zone' => '3'
)
);
Then I would like to have all $packs zones combination with those products zones.
For example, products_zones are 2, 2, 3, 2, 2, 3 then I would like something like this:
Packs:
Combination 1:
Pack 1 (when Pack zones are in Products Zones, add pack to combination and remove products from array)
Pack 1
Combination 2:
Pack 1
Pack 3
Combination 3:
Pack 1
Pack 4
Combination 4:
Pack 2
Pack 4
Combination 5:
Pack 2
Pack 2
Pack 4
I'm trying to do that with recursive function but doesn't work. I leave here a link with code:
function search_recursive( $packs = array(), $products = array(), $packs_in = array(), $pass = null ) {
foreach ($packs as $index => $pack) {
// Get zones to compare
$arr_zones = array_column($pack['zonas'], 'zona');
$products_zones = array_column($products, 'zone');
// Check if pack zones are in product zones
$cheak_arr = [];
$arr_zones_temp = $arr_zones;
foreach ($products_zones as $index2 => $temp_zone) {
if ( in_array($temp_zone, $arr_zones_temp) ) {
$cheak_arr[] = $temp_zone;
foreach ($arr_zones_temp as $key => $value) {
if ( $value == $temp_zone ) {
unset($arr_zones_temp[$key]);
break;
}
}
}
}
if ( count($arr_zones) == count($cheak_arr) ) {
// I create a index for first time
$custom_index = ($pass == null) ? $index : $pass;
// Add pack to array if pack zones are in product zones
if ( !isset($packs_in[$custom_index]) ) {
$packs_in[$custom_index] = [
'packs' => array($pack)
];
}
else {
$packs_in[$custom_index]['packs'][] = $pack;
}
// Remove products that have zones same in pack
$temp_prod = $products;
foreach ($arr_zones as $zone) {
foreach ($temp_prod as $key => $value) {
if ( $value['zone'] == $zone ) {
unset($temp_prod[$key]);
break;
}
}
}
if ( $pass != null ) {
$products = $temp_prod;
}
if ( !empty($temp_prod) ) {
// Call myself with less products and index defined
$packs_in = search_recursive( $packs, $temp_prod, $packs_in, $custom_index );
}
else if ( $pass != null ) {
break;
}
}
}
return $packs_in;
}

I think I got what you need, but I'm still a bit confused. Anyway, I suggest you to simplify you "packs" array like my code below:
<?php
$packs = array(
array(
'name' => 'Pack 1',
'zones' => array(2,2),
),
array(
'name' => 'Pack 2',
'zones' => array(2,2,2),
),
array(
'name' => 'Pack 3',
'zones' => array(2,3),
),
array(
'name' => 'Pack 4',
'zones' => array(3,3),
)
);
$products = array(
array(
'id' => '8',
'zone' => '2'
),
array(
'id' => '13',
'zone' => '3'
),
array(
'id' => '11',
'zone' => '2'
),
array(
'id' => '10',
'zone' => '2'
),
array(
'id' => '12',
'zone' => '3'
)
);
$product_zones = array_column($products, 'zone');
//let's order an change to a sequence of numbers like 22233
sort($product_zones);
$product_zones = join('', $product_zones);
$combinations = [];
//here we iterate through all packs 1->2,3,4; 2->3,4 3->4 to find if it matches
foreach($packs as $k => $pack) {
// use k+1 if you can't match the pack with itself
for ($i = $k, $c = count ($packs); $i < $c; $i++) {
//here we do the same as before to combine the packs as string, ex.: 2223
$pack_zones = array_merge($pack['zones'], $packs[$i]['zones']);
sort($pack_zones);
$pack_zones = join('', $pack_zones);
//if it's a substring of our product zones then we have a valid combination
if (strpos($product_zones, $pack_zones) !== false) {
$combinations[] = [$pack['name'], $packs[$i]['name']];
}
}
}
print_r($combinations);
result: 1,3 (22223) ; 1,4 (2233) ; 2,4 (22233) ; 3,3 (2233)

Related

Array to string conversion is not working in opencart?

Actually I want to convert array data to string data for that I
amusing implode() function by comma separator but it is throwing error.
Below is my code:-
$total_data = array();
$category_return = $this->model_catalog_category->category_name_get();
//print_r($category_return);die;
foreach ($category_return as $total) {
$total_data[] = array(
'category_id' => $total['category_id'],
'parent_id' => $total['category_id'],
'name' => $total['name']
);
}
$data = $total_data;
//print_r($data);die;
$fields = implode(',',$data);
echo $fields; die;
Try this:
$total_data = array(
array(
'category_id' => 2,
'parent_id' => 1,
'name' => 'First Cat'
),
array(
'category_id' => 1,
'parent_id' => 0,
'name' => 'Parent Cat'
),
array(
'category_id' => 3,
'parent_id' => 2,
'name' => 'Parent Cat3'
)
);
$output = implode(",", array_map(function($a) { return implode(",", $a); }, $total_data));
print_r($output);
Output:
2,1,First Cat,1,0,Parent Cat,3,2,Parent Cat3

How to copy this portion of the array to a new array in php?

I have this php array X.
X= array(
'Parent' => array(
'title' => '123',
)
)
I have this php array Y.
Y = array(
'Parent' => array(
'id' => '16',
'title' => 'T1',
),
'Children' => array(
(int) 0 => array(
'id' => '8',
'serial_no' => '1',
),
(int) 1 => array(
'id' => '9',
'serial_no' => '2',
),
(int) 2 => array(
'id' => '14',
'serial_no' => '6',
)
)
)
I want to copy the Children of array Y to the parent of array X to form array Z such that it looks like this;
Z= array(
'Parent' => array(
'title' => '123',
)
'Children' => array(
(int) 0 => array(
'serial_no' => '1'
),
(int) 1 => array(
'serial_no' => '2'
),
(int) 2 => array(
'serial_no' => '6'
)
)
)
Please note that the id key-value pair was removed from the Children of array Y.
I wrote some code of my own.
$Z = array();
$i=0;
foreach($Y as $temp)
{
$Z['Children'][$i] = $temp['Children'][$i];
unset($Z['Children'][$i]['id'];
$i++;
}
$Z['Parent']=$temp['Parent'];
Unfortunately, there is an undefined index error. How can this be done in php? Forget about my code if there are better approaches.
Actually your approach works too, but you need to iterate over sub-array:
$Z = array();
$i=0;
foreach($Y['Children'] as $temp)
{
$Z['Children'][$i] = $temp;
unset($Z['Children'][$i]['id'];
$i++;
}
or what I may do:
$Z = $X;
$Z['Children'] = array();
foreach ( $Y['Children'] as $child ) {
$Z['Children'][] = array(
'serial_no' => $child['serial_no'],
);
}
You can do like.
$Z = array();
foreach($Y['Children'] as $temp)
{
$Z['Children'][] = array('serial_no' => $temp['serial_no']);
}
$Z['Parent']=$X['Parent'];

converting plain array to multidimensional one using recursion

everyone!
I'm stuck trying write a recursive function. =(
This is my function, which, as I expected, will turn my plain array into multidimensional one.
function BuildTree($src, $index=0) {
foreach ($src as $index=>$curentItem) {
$nextItem = (is_array($src[$index+1]))?$src[$index+1]:false;
unset($src[$index]);
if ($nextItem['d']==$curentItem['d']) $brunchArray[] = $curentItem['n'];
if ($nextItem['d']>$curentItem['d']) $brunchArray['childrens'] = BuildTree($src, $index);
if (!$nextItem || $nextItem['d']<$curentItem['d']) return $brunchArray;
}
}
Input array is something like this:
$input = array (
array(
'n' => 'Articles',
'd' => 0
),
array(
'n' => 'Article 1',
'd' => 1
),
array(
'n' => 'Books',
'd' => 0
),
array(
'n' => 'Book 1',
'd' => 1
),
array(
'n' => 'Book 2',
'd' => 1
),
array(
'n' => 'Chapter 1',
'd' => 2
),
array(
'n' => 'Chapter 2',
'd' => 2
)
);
And I want it to be converted into this:
array (
array(
'n' => 'Articles',
'd' => 0,
'childrens' => array (
array(
'n' => 'Article 1',
'd' => 1
),
)
),
array(
'n' => 'Books',
'd' => 0,
'childrens' => array (
array(
'n' => 'Book 1',
'd' => 1
),
array(
'n' => 'Book 2',
'd' => 1
'childrens' => array (
array(
'n' => 'Chapter 1',
'd' => 2
),
array(
'n' => 'Chapter 2',
'd' => 2
)
)
)
)
)
)
I already spent three hours trying to solve this. =( Any help will be highly appreciated!
Here is a solution without recursion:
function convert($arr) {
$stack = array();
$output = array();
$arr[] = array('d' => -1); // Dummy record at the end
for($i = 0; $i < count($arr); $i++) {
while(!empty($stack) && $stack[count($stack) - 1]['d'] > $arr[$i]['d']) {
$current_d = $stack[count($stack) - 1]['d'];
$children = array();
while(!empty($stack) && $stack[count($stack) - 1]['d'] >= $current_d) {
$children[] = array_pop($stack);
}
$children = array_reverse($children);
if(empty($stack)) {
foreach($children as $child) {
$output[] = $child;
}
} else {
$stack[count($stack) - 1]['children'] = $children;
}
}
$stack[] = $arr[$i];
}
return $output;
}
$input = array (
array(
'n' => 'Articles',
'd' => 0
),
array(
'n' => 'Article 1',
'd' => 1
),
array(
'n' => 'Books',
'd' => 0
),
array(
'n' => 'Book 1',
'd' => 1
),
array(
'n' => 'Book 2',
'd' => 1
),
array(
'n' => 'Chapter 1',
'd' => 2
),
array(
'n' => 'Chapter 2',
'd' => 2
)
);
var_dump(convert($input));
Using the same $input:
$output = array();
function buildTree(&$input, &$output, &$current, $level = 0) {
if(!$input)
return;
$next = array_shift($input);
if($next['d'] == $level) {
$current[] = $next;
return buildTree($input, $output, $current, $level);
} else if($next['d'] == $level + 1) {
$current[count($current) - 1]['childrens'] = array($next);
return buildTree($input, $output, $current[count($current) - 1]['childrens'], $level + 1);
} else {
$output[] = $next;
return buildTree($input, $output, $output, 0);
}
}
buildTree($input, $output, $output);
var_dump($output);

PHP: Help with Sorting Array

How can I sort an associative array by a weight AND type?
Input
array(
'a' => array( 'type' => 't1', 'weight' => 1, 'text' => 'text1' ),
'b' => array( 'type' => 't1', 'weight' => 3, 'text' => 'text2' ),
'c' => array( 'type' => 't2', 'weight' => 5, 'text' => 'text3' ),
'd' => array( 'type' => 't1', 'weight' => 2, 'text' => 'text4' ),
'e' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text5' ),
'f' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text6' )
);
Desired Output
array(
'a' => array( 'type' => 't1', 'weight' => 1, 'text' => 'text1' ),
'd' => array( 'type' => 't1', 'weight' => 2, 'text' => 'text4' ),
'b' => array( 'type' => 't1', 'weight' => 3, 'text' => 'text2' ),
'e' => array( 'type' => 't2', 'weight' => 1, 'text' => 'text5' ),
'f' => array( 'type' => 't2', 'weight' => 1, 'text' => 'text6' ),
'c' => array( 'type' => 't2', 'weight' => 5, 'text' => 'text3' )
);
Type "t2" must appear at end of array, all other types at start.
Weight must be sorted after type.
I am using uasort with a custom compare function, but am struggling. Here is what I have, but it doesn't work:
function my_comparer($a, $b) {
return ( $a['type'] !== 't2' && $b['type'] === 't2' )
? -1
: $a['weight'] - $b['weight'];
}
Your function doesn't take account of ($a['type']=='t2')
function my_comparer($a, $b) {
if ( ($a['type']==='t2') && ($b['type']!=='t2')) return -1;
if ( ($b['type']==='t2') && ($a['type']!=='t2')) return 1;
return ($a['weight'] - $b['weight']);
}
Try this:
function my_comparer($a, $b) {
if( $a['type'] == $b['type'] ){
return $a['weight'] - $b['weight'];
}else{
if( $a['type'] > $b['type'] ) return 1;
else return -1;
}
}
(warning, this is untested)
Simpler way would be array_multisort
$data = array(
'a' => array( 'type' => 't1', 'weight' => 1, 'text' => 'text1' ),
'b' => array( 'type' => 't1', 'weight' => 3, 'text' => 'text2' ),
'c' => array( 'type' => 't2', 'weight' => 5, 'text' => 'text3' ),
'd' => array( 'type' => 't1', 'weight' => 2, 'text' => 'text4' ),
'e' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text5' ),
'f' => array( 'type' => 't2', 'weight' => 4, 'text' => 'text6' )
);
// Obtain a list of columns
foreach ($data as $key => $row) {
$type[$key] = $row['type'];
$weight[$key] = $row['weight'];
}
array_multisort($type, SORT_ASC, $weight, SORT_ASC, $data);
Plus this works if you add any number of types you want sorted in the same way.
Helper function:
function arrayColumnSort(&$array, $directions) {
// collect columns
$columnNames = array_keys($directions);
$columns = array();
foreach ($array as $row) {
foreach ($columnNames as $columnName) {
if (!isset($columns[$columnName])) {
$columns[$columnName] = array();
}
$columns[$columnName][] = isset($row[$columnName]) ? $row[$columnName] : null;
}
}
// build array_multisort params
$params = array();
foreach ($directions as $columnName => $direction) {
$params = array_merge(
$params,
array($columns[$columnName]),
is_array($direction) ? $direction : array($direction)
);
}
$params[] =& $array;
// sort
call_user_func_array('array_multisort', $params);
}
Call:
arrayColumnSort($data, array(
'type' => SORT_ASC,
'weight' => SORT_ASC,
));

Convert 2d array into 3d with PHP

There are simple 2d array with some sort of tree like this:
node1
node2
node3
It's structure is:
array(
array (
'id' : 1,
'pid': 0,
'title' : 'node1',
'level' : 1
),
array (
'id' : 2,
'pid': 1,
'title' : 'node2',
'level' : 2
),
array (
'id' : 3,
'pid': 2,
'title' : 'node3',
'level' : 3
),
)
Is there solutions with PHP to convert this array into:
array(
array (
'id' : 1,
'title' : 'node1',
'child' : array (
'id' : 2,
'title' : 'node2',
'child' : array (
'id' : 3,
'title' : 'node3',
),
),
)
...
)
Found #SO PHP Traversing Function to turn single array into nested array with children - based on parent id
$inArray = array(
array('ID' => '1', 'parentcat_ID' => '0'),
array('ID' => '2', 'parentcat_ID' => '0'),
array('ID' => '6', 'parentcat_ID' => '1'),
array('ID' => '7', 'parentcat_ID' => '1'),
array('ID' => '8', 'parentcat_ID' => '6'),
array('ID' => '9', 'parentcat_ID' => '1'),
array('ID' => '13', 'parentcat_ID' => '7'),
array('ID' => '14', 'parentcat_ID' => '8'),
);
function makeParentChildRelations(&$inArray, &$outArray, $currentParentId = 0) {
if(!is_array($inArray)) {
return;
}
if(!is_array($outArray)) {
return;
}
foreach($inArray as $key => $tuple) {
if($tuple['parentcat_ID'] == $currentParentId) {
$tuple['children'] = array();
makeParentChildRelations($inArray, $tuple['children'], $tuple['ID']);
$outArray[] = $tuple;
}
}
}
$outArray = array();
makeParentChildRelations($inArray, $outArray);
print_r($outArray);
<?php
$p = array(0 => array());
foreach($nodes as $n)
{
$pid = $n['pid'];
$id = $n['id'];
if (!isset($p[$pid]))
$p[$pid] = array('child' => array());
if (isset($p[$id]))
$child = &$p[$id]['child'];
else
$child = array();
$p[$id] = $n;
$p[$id]['child'] = &$child;
unset($p[$id]['pid']);
unset($p[$id]['level']);
unset($child);
$p[$pid]['child'][] = &$p[$id];
// $p[$pid]['child'] = &$p[$id]; // or this, if only one child
}
$nodes = $p['0']['child'];
unset($p);
?>
If each node can only have one child, then replace the one line with $p[$pid]['child'] = &$p[$id];.
(Edit: fixed it to work regardless of how the nodes are sorted.)

Categories