cartesian product with PHP (id, name, variants) - php

Can you help me with generating caresian product.
It is similar to this stackoverflow. I want generate inputs so I need keep ID.
Example:
my input data:
[
1 => [
id => 1,
name => "Color",
options => [
5 => [
id => 5,
name => "Red"
],
6 => [
id => 6,
name => "Blue"
]
]
],
2 => [
id => 2,
name => "Size",
options => [
7 => [
id => 7,
name => "S"
],
8 => [
id => 8,
name => "M"
]
]
],
// etc
]
result I expect:
[
"5-7" => "Red / S",
"5-8" => "Red / M",
"6-7" => "Blue / S",
"6-8" => "Blue / M"
]
I need generic function for any number of properties/options..

Nested loop man, each entry of array 1 has to be linked with every entry of array2.
$finalArray = array();
foreach (array1 as $key1 as $value1){
foreach (array2 as $key2 as$value2){
echo $value1 . " - " .$value2."<br/>";
$finalArray[$key1.'-'.$key2] = $value1 ." - ".$value2;
}
}
the finalArray will be having what you need.

That is actually working code for now but don't know how much is efficient.
// filter out properties without options
$withOptions = array_filter($properties, function($property) {
return count($property['options']) > 0;
});
$result = [];
$skipFirst = true;
foreach ($withOptions as $property) {
if ($skipFirst) {
foreach (reset($withOptions)['options'] as $id => $option) {
$result[$id] = $option['name'];
}
$skipFirst = false;
continue;
}
foreach ($result as $code => $variant) {
foreach ($property['options'] as $id => $option) {
$new = $code . "-" . $id;
$result[$new] = $variant . " / " . $option['name'];
unset($result[$code]);
}
}
}

Related

Group an array based on common value

I have an array with common product code & product name.
For each product_code can have two types of cha_sty_id i.e push or pull.
This is an array structure I have.
$array = [
0 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PUSH",
"chs_name" => "WF"
],
1 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PUSH",
"chs_name" => "WFR"
],
2 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PUSH",
"chs_name" => "STK Food"
],
3 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "4 Stars"
],
4 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "5 Stars"
],
5 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "Modern Thai"
],
6 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "BBQ Buffet"
],
7 => [
"product_code" => "67021687",
"product_name" => "Spaces",
"cha_sty_id" => "PULL",
"chs_name" => "Chinese"
]
];
Now I want result something like:
0 => [
'product_code' => 67021687,
'product_name' => 'Spaces.
'push => array(....ALL chs_name for push),
'pull' => array with chs_name for pull
]
I have tried some code
$list = array();
foreach ($records as $data) {
$list[$data['product_code']][] = $data;
if($data['cha_sty_id'] == 'PUSH') {
$list[$data['product_code']]['push'] = $data['chs_name'];
} else {
$list[$data['product_code']]['pull'] = $data['chs_name'];
}
}
But I could not solve it.
Can anybody pls help me.
Thank You.
How about this modify your foreach loop to this:
$list = array();
foreach ($records as $data) {
$code = $data['product_code']; // as key
if (!isset($list[$code])) { // set new array if not exist
$list[$code] = array("product_code" => $code, "product_name" => $data['product_name'], "push" => [], "pull" => []);
}
$subKey = strtolower($data['cha_sty_id']); // get push / pull as new subkey
$list[$code][$subKey][] = $data['chs_name']; // append to the array
}
You can use array_values to remove the code keys from $list after the loop if not needed
You can use array_walk,array_push
$res = [];
array_walk($array, function($v, $k) use (&$res){
if(in_array($v['product_code'], array_column($res, 'product_code'))){
array_push($res[$v['product_code']]["push"], $v['chs_name']);
array_push($res[$v['product_code']]["pull"], $v['chs_name']);
}else{
$res[$v['product_code']] = [
"product_code" => $v['product_code'],
"product_name" => $v['product_name'],
"push" => [$v['chs_name']],
"pull" => [$v['chs_name']]
];
}
});
echo '<pre>';
print_r(array_values($res));
DEMO HERE
There is no need for any conditional expressions while partially pivoting your data into groups. Use the product_code values as temporary first level keys and use the cha_sty_id values as dynamic second level keys. Re-index the result array after the loop finishes with array_values().
One approach uses a body-less foreach as explained here.
Code: (Demo)
$result = [];
foreach (
$array
as
[
'product_code' => $productCode,
'cha_sty_id' => $id,
'product_code' => $result[$code]['product_code'],
'product_name' => $result[$code]['product_name'],
'chs_name' => $result[$code][strtolower($id)][]
]
);
var_export(array_values($result));
A more traditional style is to group and pivot inside the body of the loop.
Code: (Demo)
$result = [];
foreach ($array as $row) {
$result[$row['product_code']]['product_code'] = $row['product_code'];
$result[$row['product_code']]['product_name'] = $row['product_name'];
$result[$row['product_code']][strtolower($row['cha_sty_id'])][] = $row['chs_name'];
}
var_export(array_values($result));
Due to the fact that the group logic is possibly going to return an array size that differs from the input array, array_reduce() is the most appropriate functional iterator for this task.
Code: (Demo)
var_export(
array_values(
array_reduce(
$array,
function($result, $row) {
$result[$row['product_code']]['product_code'] = $row['product_code'];
$result[$row['product_code']]['product_name'] = $row['product_name'];
$result[$row['product_code']][strtolower($row['cha_sty_id'])][] = $row['chs_name'];
return $result;
},
[]
)
)
);
All techniques above produce the exact same result.

How to create dynamic combination with php?

I have 3 array like
$arr = [
"color" => [["name"=>"red"]],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]]
]
$combo = array();
foreach ($arr['size'] as $size) {
foreach($arr['color'] as $color){
foreach ($arr['type'] as $type) {
$variant = json_encode(['size' => $size->name, 'color' =>
$color->name, 'type' => $type->name]);
array_push($combo,$variant);
}
}
}
echo $combo;
// result
0 => "{"size":"15 inch","color":"yellow","type":"metal"}"
1 => "{"size":"18 inch","color":"yellow","type":"plastic"}"
It works properly but but there is can be less or more variants. How can I handle this.
For example
$arr = [
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]]
]
Or
$arr = [
"color" => [["name"=>"red"]],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]],
"brand" => [['name' => 'something']],
]
For what i understand, you have to combine the arrays of properties into one array of
object.
I have to leave now, but if you need a explanation leave a comment and i updated the answers
$arr = [
"color" => [["name"=>"red"],['name'=>'yellow']],
"size" => [["name"=>"18 inch"], ["name"=>"15 inch"]],
"type" => [["name"=>"plastic"]],
"brand" => [['name' => 'something']],
];
function runFor($arr ,&$array, $keys,$index,&$positions){
foreach ($arr[$keys[$index]] as $key => $espec){
$positions[$keys[$index]] = $key;
if($index + 1 < count($keys)){
runFor($arr,$array,$keys, $index+1,$positions);
}else{
$item = (object)[];
foreach ($keys as $key){
$item->$key = $arr[$key][$positions[$key]]['name'];
}
array_push($array,$item);
}
unset($positions[$keys[$index]]);
}
}
$array = array();
$keys = array_keys($arr);
$positions = [];
runFor($arr,$array,$keys,0,$positions);
$combo = array();
foreach ($array as $item){
array_push($combo,json_encode($item));
}
var_dump($combo);

PHP - Return single row from associated arrays

Let say I have the datas in JSON,
3 people have different datas such as New only / New and Old / Old and New.
I tried using isset($_GET['NoID']); which is
http://localhost/test.php?NoID=31331 // Stan Lee
http://localhost/test.php?NoID=31332 // Mary Jane
http://localhost/test.php?NoID=31335 // John Doe
And the result are:
// Stan Lee
{
- Table: [
- {
Name: "Stan Lee",
NoID: "31331",
Type: "New",
- #attributes: {
id: "Table1",
rowOrder: "0",
}
},
]
}
// Mary Jane
{
- Table: [
- {
Name: "Mary Jane",
NoID: "31332",
Type: "New",
- #attributes: {
id: "Table1",
rowOrder: "0",
}
},
- {
Name: "Mary Jane",
NoID: "31333",
Type: "Old",
- #attributes: {
id: "Table2",
rowOrder: "1",
}
},
]
}
// John Doe
{
- Table: [
- {
Name: "John Doe",
NoID: "31334",
Type: "Old",
- #attributes: {
id: "Table1",
rowOrder: "0",
}
},
- {
Name: "John Doe",
NoID: "31335",
Type: "New",
- #attributes: {
id: "Table2",
rowOrder: "1",
}
},
]
}
I want to return which is condition is New only (Single row).
I tried to foreach() then strict statement for New and break, also I tried array_filter() and sort(). Those function didn't work out to return New only.
My code I tried so far:
foreach ($data['Table'] as $value) {
if (is_array($value) && $value['Type'] == "New") {
json($value);
break;
} elseif (is_string($value)) {
json($value);
break;
}
}
And the output is
Notice: Undefined index: Type
"New"
Both Mary Jane & John Doe gimme the right output, but Stan Lee didn't work.
Anyone can help me out?
Thank you!
hi bro i have checked you code and i just remove the break try this:
$data = ["Table" => [[
"Name" => "Stan Lee",
"NoID" => "31331",
"Type" => "New",
"attributes" =>[
"id"=>"Table1",
"rowOrder"=> "0"
]
],
[
"Name" => "Mary Jane",
"NoID" => "31332",
"Type" => "New",
"attributes" =>[
"id"=>"Table1",
"rowOrder" => "0"
]
],
[
"Name" => "Mary Jane",
"NoID" => "31333",
"Type" => "Old",
"attributes" =>[
"id"=>"Table2",
"rowOrder" =>"1"
]
],
[
"Name" => "John Doe",
"NoID" => "31334",
"Type" => "Old",
"attributes" =>[
"id"=>"Table1",
"rowOrder"=>"0"
]
],
[
"Name" => "John Doe",
"NoID" => "31335",
"Type" => "New",
"attributes" =>[
"id"=>"Table2",
"rowOrder" => "1"
]
],
]
];
foreach ($data['Table'] as $value) {
if (is_array($value) && $value['Type'] == "New") {
echo '<pre>';
print_r($value);
echo '</pre>';
} elseif (is_string($value)) {
echo '<pre>';
print_r($value);
echo '</pre>';
break;
}
}
and here is the output:
Array
(
[Name] => Stan Lee
[NoID] => 31331
[Type] => New
[attributes] => Array
(
[id] => Table1
[rowOrder] => 0
)
)
Array
(
[Name] => Mary Jane
[NoID] => 31332
[Type] => New
[attributes] => Array
(
[id] => Table1
[rowOrder] => 0
)
)
Array
(
[Name] => John Doe
[NoID] => 31335
[Type] => New
[attributes] => Array
(
[id] => Table2
[rowOrder] => 1
)
)
Let me know if this is what you need. feel free to ask.
Remove the break; from the foreach() loop.
break will interrupt the loop and no more array keys/values are treated anymore.
PHP break
edit
Probable you do not want to sent the json each time the condition is met.
So before the foreach() create variable $output and collect matched values to it $output[] = $value;. And finally send the whole output using json($output);
<?php
$data = [
"Table" => [
"Type" => "New"
],
[
1 => ["Type" => "New"],
2 => ["Type" => "Old"],
],
[
1 => ["Type" => "Old"],
2 => ["Type" => "New"],
]
];
foreach ($data['Table'] as $key => $value) {
If($key == 'Type' and $value == 'New'){
$output[] = $value;
}
Maybe this will help you:
$newArray = array();
foreach($data as $key => $d){
if(sizeof($d) > 1){
foreach($d as $key1 => $d1){
if(strtolower($d1['Type']) == 'new'){
$newArray[$key1]['Type'] = $d1['Type'];
}
}
}else{
if(strtolower($d['Type']) == 'new'){
$newArray[$key]['Type'] = $d['Type'];
}
}
}
print_r(json_encode($newArray));
Solution:
function arraySearch($array,$keyword="type",$value="New",$results=[]) {
foreach ( $array as $key => $val ) {
if(is_array($val)){
if(array_key_exists($keyword,$val)){
if ($val[$keyword] === $value ) {
$results[] = $key;
}
}else{
arraySearch($array,$keyword,$value,$results);
}
}
}
return json($results);
}
Call to function:
echo arraySearch($data['Table']);
Use array_filter like this, demo
array_filter($data, function($v){
return count($v) == 1 && $v['Type'] == 'New';
})
<?php
foreach ($data['Table'] as $value) {
foreach ($value as $data) {
if(in_array('New', $data)) {
//here you can code
echo "<pre>";
print_r($data);
}
}
}
Result: [{"0":"New","1":"New","4":"New"}]
<?php
$data = ["Table" => [[
"Name" => "Stan Lee",
"NoID" => "31331",
"Type" => "New",
"attributes" =>[
"id"=>"Table1",
"rowOrder"=> "0"
]
],
[
"Name" => "Mary Jane",
"NoID" => "31332",
"Type" => "New",
"attributes" =>[
"id"=>"Table1",
"rowOrder" => "0"
]
],
[
"Name" => "Mary Jane",
"NoID" => "31333",
"Type" => "Old",
"attributes" =>[
"id"=>"Table2",
"rowOrder" =>"1"
]
],
[
"Name" => "John Doe",
"NoID" => "31334",
"Type" => "Old",
"attributes" =>[
"id"=>"Table1",
"rowOrder"=>"0"
]
],
[
"Name" => "John Doe",
"NoID" => "31335",
"Type" => "New",
"attributes" =>[
"id"=>"Table2",
"rowOrder" => "1"
]
],
]
];
$build = [];
$output = [];
$i= 0;
foreach ($data as $value) {
foreach ( $value as $key => $val) {
if(!is_array($val) AND $val== "New"){
$build[$i][0] = $val;
$output = $build;
}else if(is_array($val) AND $val["Type"] === "New"){
$build[$i][$key] = "New";
$output = $build;
}
}
$i++;
}
print_r(json_encode($output));
?>

Multidimensional array to text using only keys

I have an array of this sort:
$array = [
"Darren" => [
"age" => "18",
"work" => [
"occupation" => "developer",
"company" => "ABC Ltd"
]
],
"John" => [
"age" => "24",
"work" => [
"occupation" => "developer",
"company" => "ABC Ltd",
"url" => "www.example.com"
],
]
]
And would like to merge the keys with a dot in between, depending on the array's hierachy:
"Darren.age"
"Darren.work.occupation"
"Darren.work.company"
...
The function that I made so far is
public function buildExpressionKey($array, $parentKey = null){
$expression = [];
foreach($array as $key=>$value){
if(is_array($value)){
array_push($expression, $parentKey. implode(".",
$this->buildExpressionKey($value, $key)));
}else{
array_push($expression, $key);
}
}
return $expression;
}
it is returning this value at the moment:
[
[0] => "age.Darrenoccupation.company"
[1] => "age.Johnoccupation.company.url"
]
Was wondering if it is possible to make a function which automatically does merges the keys like that, thanks in advance :)
What you are currently asking for:
<?php
$people =
[
'John' =>
[
'Occupation' => 'Developer',
'Age' => 18
],
'Darren' =>
[
'Occupation' => 'Manager',
'Age' => 40
]
];
foreach($people as $name => $value)
foreach($value as $k => $v)
$strings[] = $name . '.' . $k;
var_export($strings);
Output:
array (
0 => 'John.Occupation',
1 => 'John.Age',
2 => 'Darren.Occupation',
3 => 'Darren.Age',
)
Managed to resolve this issue :)
/**
* #param $array
* #return array
*/
public function buildExpressionKey($array){
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($array));
$keys = array();
foreach ($iterator as $key => $value) {
// Build long key name based on parent keys
for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
$key = $iterator->getSubIterator($i)->key() . '.' . $key;
}
$keys[] = $key;
}
return $keys;
}
Found something similar on here: Get array's key recursively and create underscore separated string

Loop array content value consist of single value and array

I have tried to loop this array but I still get error
I have an array like this:
1 => ["name"=>"A", "related"=>[
["signal"=>"A1", "color"=>"green"],
["signal"=>"A2", "color"=>"lime"],
["signal"=>"A3","color"=>"yellowGreen"]
]]
2 => ["name"=>"B", "related"=>[
["signal"=>"B1", "color"=>"Red"],
["signal"=>"B2", "color"=>"Pink"]
]]
How to display as - A : Green, lime, yellowGreeb
- B : Red, Pink
This is my code that I've tried to display as above format
foreach($arr as $key => $value){
echo $value["name"];
foreach($value["related"] as $k){
echo $k["color"] . ",";
}
}
It throw error this array dont has $value["related"] index. But It can echo the $value["name"]???
Thank you!
Find the solution as below:
$array = [1 => [
"name" => "A",
"related" => [
["signal" => "A1", "color" => "green"],
["signal" => "A2", "color" => "lime"],
["signal" => "A3", "color" => "yellowGreen"]
]
],
2 => ["name" => "B", "related" => [
["signal" => "B1", "color" => "Red"],
["signal" => "B2", "color" => "Pink"]
]]
];
foreach ($array as $ar) {
$new_arr = array_column($ar['related'], 'color');
$required_string = implode(', ', $new_arr);
echo $ar['name'].' : ' .$required_string;
echo "<br />";
}
For PHP Version < 5.5 you can use below solution:
foreach ($array as $ar) {
$new_arr = array_map(function ($value) {
return $value['color'];
}, $ar['related']);
$required_string = implode(', ', $new_arr);
echo $ar['name'].' : ' .$required_string;
echo "<br />";
}
you can found more detail about foreach loop at http://php.net/manual/en/control-structures.foreach.php

Categories