I'm working on processing data returned from a form but because I've had to manually assign ids to the select dropdowns (so that I can attach a help button to the headings) I can't find an example to work from.
The array being returned looks like this:
[10]=>
string(1) "0"
[11]=>
string(1) "0"
[12]=>
string(1) "0"
[20]=>
string(1) "0"
[21]=>
string(1) "0"
[22]=>
string(1) "0"
["comments"]=>
string(0) ""
["submitbutton"]=>
string(12) "Save changes"
What I need to do is group all that start with a unique number (i.e. 1,2...) and ignore the comments and submitbutton elements.
In other words, I want it to look like this:
id = 1
criteria0 = 0
criteria1 = 0
criteria2 = 0
id = 2
criteria0 = 0
criteria1 = 0
criteria2 = 0
Think I would just use a delimiter, eg:
In the form
foreach (array(1,2) as $id) {
foreach (array(1,2,3) as $criteria) {
$key = $id . '_' . $criteria;
$options[$key] = "Your description for id $id, criteria $criteria";
}
}
$attributes = array('multiple' => 'multiple', 'size' => 10);
$form->addElement('select', 'criteria', get_string('criteria', 'component'), $options, $attributes);
Then in the results
$formdata = $mform->get_data();
...
$results = array();
foreach ($formdata->criteria[$key] as $key => $value) {
list($id, $criteria) = explode('_', $key);
$results[$id][$criteria] = $value;
}
Also for reference, Moodle has a selectgroups field type. You will still need to use a unique key but you can group the options.
foreach (array(1,2) as $groupid) {
foreach (array(1,2,3) as $criteria) {
$key = $groupid . '_' . $criteria;
// Use a group.
$options[$groupid][$key] = "Your description for id $groupid, criteria $criteria";
}
}
$attributes = array('multiple' => 'multiple', 'size' => 10);
// Use selectgroups.
$form->addElement('selectgroups', 'criteria', get_string('criteria', 'component'), $options, $attributes);
Related
I got some array inside array and I want to get all the value of that and store it on variable. This is the structure of my array :
array(5) { ["InventoryID"]=> string(2) "43"
["Price"]=> string(5) "45.36"
["Warehouse"]=> array(2) { ["WID"]=> string(1) "1"
["Quantity"]=> string(1) "12"
}
["Name"]=> string(48) "Bottle"
["SKU"]=> string(8) "M123"
}
array(5) { ["InventoryID"]=> string(2) "51"
["Price"]=> string(5) "21.67"
["Warehouse"]=> array(2) { ["WID"]=> string(1) "1"
["Quantity"]=> string(1) "40"
}
["Name"]=> string(48) "Glass"
["SKU"]=> string(8) "M124"
}
What I want is to get all the value of that array and store it in variable like this :
$inventoryid = 43;
$price = 45.36;
$wid = 1;
$quantity = 12;
$name = 'Bottle';
$sku = 'M123';
What I do till now is I looping that array in foreach but I can't get the second array value. This is what I do till now :
foreach($array as $row)
{
$inventoryid = $row['InventoryID'];
$price = $row['Price'];
$name = $row['Name'];
$sku = $row['SKU'];
foreach($row['Warehouse'] as $row2)
{
$wid = $row2['WID'];
$quantity = $row2['Quantity'];
}
}
How can I do that ? Please anyone give me some code example with foreach to get the value.
I'm struggling to fully understand what benefit you're getting from having these values as variables rather than part of an array. You're still able to access the values quite easily.
Anyway, based on your comment it appears the issue is with the nested array. You don't need a foreach to access those values.
Example:
$wid = $row['Warehouse']['WID'];
$quantity = $row['Warehouse']['Quantity']
Documentation: http://php.net/manual/en/language.types.array.php
you can use recursive for this.
class ProductData
{
public function walkRecursive($a) {
asort($a); //Sort top down
foreach($a as $k => $v){
if(is_array($v)){
$this->walkRecursive($v);
}else{
$this->{$k} = $v;
}
}
return $this;
}
}
$array = array(
"SKU" => "Test1",
"Warehouse" => array("WID" => 1, "Quantity" => 2),
"Name" => "Product1"
);
$d = new ProductData();
$product = $d->walkRecursive($array);
You can now do: $product->SKU. Or $product->Quantity or $Product->Name
$global_models =
array(12) {
["page.login"]=>
string(1) "2"
["page.item.id"]=>
string(3) "new"
["page.content.title"]=>
string(0) ""
["page.trigger.date"]=>
string(0) ""
["page.trigger.url"]=>
string(0) ""
["page.trigger.admin_only"]=>
string(1) "N"
["page.content.body"]=>
string(0) ""
["page..ga"]=>
string(27) "GA1.2.1694644634.1491872034"
["prompt.message"]=>
string(0) ""
["prompt.error"]=>
string(0) ""
["page.tags"]=>
array(1) {
["name"]=>
array(2) {
[0]=>
string(2) "xx"
[1]=>
string(2) "yy"
}
}
["page.custom"]=>
array(2) {
["header"]=>
array(2) {
[0]=>
string(0) "1"
[1]=>
string(1) "a"
}
["value"]=>
array(2) {
[0]=>
string(0) "2"
[1]=>
string(1) "b"
}
}
}
Code:
foreach ($global_models as $var => $data) {
// when model data is an array
if (is_array($data)) {
// fetch for blocks and render loops
$forblocks = array();
preg_match_all('/(?<block>\[for:'.$var.'\](?<content>[\s\S]+)\[end:'.$var.'\])/ix', $view_output, $forblocks, PREG_SET_ORDER);
if (count($forblocks)) {
foreach ($forblocks as $foundForBlock) {
$foreach_data = '';
foreach ($data as $mykey => $row) {
// set model values within the loop, ex: blocks.x value
$block_content = $foundForBlock['content'];
foreach ($row as $subvar => $value) {
if (!is_array($value)) {
$block_content = str_replace('['.$var.'.'.$subvar.']', $value, $block_content);
//$block_content = str_replace('['.$var.'.'.$mykey.']', $value, $block_content);
}
}
// append the parsed new block (of for loop) as processed view to render (ifs and setters for example)
$foreach_data .= $this->process_view($controller, $block_content, $recursion_level + 1);
}
$view_output = str_replace($foundForBlock['block'], $foreach_data, $view_output);
}
}
} else {
// simple model, replace model with value ex: "[stats.x]" by "18"
$view_output = str_replace('['.$var.']', $data, $view_output);
}
}
Issue:
Key to value pair works
my blocks of data don't work...
$viewoutput =
"
[page.login]
"
should result in
"
2
"
This:
$viewoutput =
"
[for:page.custom]
[page.custom.header] - [page.custom.value]
[end:page.custom]
"
should result in
"
1 - 2
a - b
"
This:
$viewoutput =
"
[for:page.tags]
[page.tags.name]
[end:page.tags]
"
should result in
"
xx
yy
"
I've refactored my code about 20 times and each time I get a headache...!
Someone please help?
Thanks and viva la community! :)
I have tried my self best to get it done. I know this is not a generic solution but it will solve your current problem. You must use different function for using loop([for:page.custom]) and simple([page.login]) attribute. I have already went through this issue. I also solved one of my problem by this, Here you should define seperate function which will first decide which function will handle modification whether it is for loop or for simple. But for now i have fixed your issue with a single php function.
Try this code snippet here
<?php
ini_set('display_errors', 1);
$global_models = array(
"page.login" => "2",
"page.item.id" => "new",
"page.content.title" => "",
"page.trigger.date" => "",
"page.trigger.url" => "",
"page.trigger.admin_only" => "N",
"page.content.body" => "testing",
"page..ga" => "GA1.2.1694644634.1491872034",
"prompt.message" => "",
"prompt.error" => "",
"page.tags" =>
array(
"name" =>
array(
0 => "xx",
1 => "yy"
)
),
"page.custom" =>
array(
"header" =>
array(
0 => "1",
1 => "a",
),
"value" =>
array(
0 => "2",
1 => "b",
)
)
);
$viewoutput =
"
[page.content.body]
[for:page.custom]
[page.custom.header] - [page.custom.value]
[end:page.custom]
";
echo modify($viewoutput);
function modify($viewoutput)
{
$returnString="";
global $global_models;
$segments=explode("\n", $viewoutput);
$counter=0;
while(count($segments)>0)
{
$segment=$segments[$counter];
if (preg_match("/\[for:\K([\w\.]+)\]/", $segment,$matches))
{
unset($segments[$counter]);
$counter++;
$segment=$segments[$counter];
$pointer=0;
$data=array();
preg_match_all("/\.([\w]+)\]/", $segment,$segmentMatches);
for($x=0;$x<count($global_models[$matches[1]][$segmentMatches[1][0]]);$x++)
{
$newString=$segment;
foreach($segmentMatches[1] as $toReplace)
{
$newString= str_replace("[".$matches[1].".".$toReplace."]", $global_models[$matches[1]][$toReplace][$x], $newString);
}
$data[]=$newString;
}
}
elseif(preg_match("/\[end:\K([\w\.]+)\]/", $segment))
{
$returnString.= implode("\n", $data);
}
elseif(preg_match("/\[([\w\.]+)\]/", $segment,$matches1) && !preg_match("/\[for:\K([\w\.]+)\]/", $segment,$matches))
{
$returnString=$returnString.$global_models[$matches1[1]]."\n";
}
else
{
$returnString=$returnString.$segment."\n";
}
unset($segments[$counter]);
$counter++;
}
return $returnString;
}
Fixed myself...
// process shared models (variables)
foreach ($global_models as $var => $data) {
// when model data is an array
if (is_array($data)) {
// fetch for blocks and render loops
$forblocks = array();
preg_match_all('/(?<block>\[for:'.$var.'\](?<content>[\s\S]+)\[end:'.$var.'\])/ix', $view_output, $forblocks, PREG_SET_ORDER);
if (count($forblocks)) {
foreach ($forblocks as $foundForBlock) {
$block_content = array();
foreach ($data as $mykey => $row) {
//$foreach_data = '';
// set model values within the loop, ex: blocks.x value
foreach ($row as $subvar => $value) {
if (!isset($block_content[$subvar])) $block_content[$subvar] = $foundForBlock['content'];
if (!is_array($value)) {
if (is_numeric($subvar)) {
$block_content[$subvar] = str_replace('['.$var.'.'.$mykey.']', $value, $block_content[$subvar]);
}
}
}
// append the parsed new block (of for loop) as processed view to render (ifs and setters for example)
}
$block_content = implode("\n", $block_content);
$view_output = str_replace($foundForBlock['block'], $block_content, $view_output);
}
}
} else {
// simple model, replace model with value ex: "[stats.x]" by "18"
$view_output = str_replace('['.$var.']', $data, $view_output);
}
}
Removing an array if there is a duplicate in inner array for example - As we see there is [0]['user'] and its 1, the same appears in the array 1, my desired array would only contain one of the arrays it doesn't matter which one - also would be nice if I would get a returned message that there were duplicates, the array length can vary from 1 to 10 for example. I tried some codes provided already here on stackoverflow for unique multidementional arrays but non seems to be working for me.
And this is the html method. The users can duplicate because of selection of the same user name
array(3) {
[0]=>
array(6) {
["user"]=>
string(1) "1"
["role"]=>
string(1) "1"
["can_edit"]=>
NULL
["can_read"]=>
NULL
["can_execute"]=>
NULL
["is_admin"]=>
NULL
}
[1]=>
array(6) {
["user"]=>
string(1) "1"
["role"]=>
string(1) "2"
["can_edit"]=>
NULL
["can_read"]=>
NULL
["can_execute"]=>
NULL
["is_admin"]=>
NULL
}
}
Code used for the example output
foreach ($this->input->post() as $key => $value)
{
if(preg_match("/^user.{1,2}$/",$key)>0) {
$postvars[] = $key;
}
if(preg_match("/^user.{1,2}$/",$key)>0) {
$postvalues[] = $value;
}
}
$filterArray = array_combine($postvars, $postvalues);
function array_unique_multidimensional($input)
{
$serialized = array_map('serialize', $input);
$unique = array_unique($serialized);
return array_intersect_key($input, $unique);
}
foreach (array_unique_multidimensional($postvars) as $key)
{
preg_match("|\d+|", $key, $m);
$user = $filterArray[$key];
$role = $this->input->post('role'.$m[0]);
$can_edit = $this->input->post('can_edit'.$m[0]);
$can_read = $this->input->post('can_read'.$m[0]);
$can_execute = $this->input->post('can_execute'.$m[0]);
$is_admin = $this->input->post('is_admin'.$m[0]);
$records[] = array('user' => $user,'role'=>$role,'can_edit'=>$can_edit,'can_read' =>$can_read,'can_execute' =>$can_execute,'is_admin'=>$is_admin);
}
var_dump($records);
var_dump(array_unique_multidimensional($records));
This question already has answers here:
array_count_values() with objects as values
(3 answers)
Closed 6 months ago.
How can I prevent duplicating the same block of code for each value that I want to search for?
I want to create a new array ($result) by counting for specific values within another multi-dimensional array ($data).
$result = array();
$result['Insulin'] = count(array_filter($data,function ($entry) {
return ($entry['choice'] == 'Insulin');
}
)
);
$result['TZD'] = count(array_filter($data,function ($entry) {
return ($entry['choice'] == 'TZD');
}
)
);
$result['SGLT-2'] = count(array_filter($data,function ($entry) {
return ($entry['choice'] == 'SGLT-2');
}
)
);
$data array example:
array(2) {
[0]=>
array(9) {
["breakout_id"]=>
string(1) "1"
["case_id"]=>
string(1) "1"
["stage_id"]=>
string(1) "1"
["chart_id"]=>
string(1) "1"
["user_id"]=>
string(2) "10"
["region"]=>
string(6) "Sweden"
["choice"]=>
string(7) "Insulin"
["switched_choice"]=>
NULL
["keep"]=>
string(1) "1"
}
[1]=>
array(9) {
["breakout_id"]=>
string(1) "1"
["case_id"]=>
string(1) "1"
["stage_id"]=>
string(1) "1"
["chart_id"]=>
string(1) "1"
["user_id"]=>
string(1) "7"
["region"]=>
string(6) "Sweden"
["choice"]=>
string(7) "Insulin"
["switched_choice"]=>
NULL
["keep"]=>
string(1) "1"
}
}
You may convert your anonymous function into a closure with the use keyword. Pass in a string variable for the value you want to match.
// Array of strings to match and use as output keys
$keys = array('Insulin','TZD','SGLT-2');
// Output array
$result = array();
// Loop over array of keys and call the count(array_filter())
// returning the result to $result[$key]
foreach ($keys as $key) {
// Pass $key to the closure
$result[$key] = count(array_filter($data,function ($entry) use ($key) {
return ($entry['choice'] == $key);
}));
}
Converting your var_dump() to an array and running this against it, the output is:
Array
(
[Insulin] => 2
[TZD] => 0
[SGLT-2] => 0
)
You can simplify it with array_count_values() as well:
$result2 = array_count_values(array_map(function($d) {
return $d['choice'];
}, $data));
print_r($result2);
Array
(
[Insulin] => 2
)
If you need zero counts for the missing ones, you may use array_merge():
// Start with an array of zeroed values
$desired = array('Insulin'=>0, 'TZD'=>0, 'SGLT-2'=>0);
// Merge it with the results from above
print_r(array_merge($desired, $result2));
Array
(
[Insulin] => 2
[TZD] => 0
[SGLT-2] => 0
)
Not the most efficient algorithm in terms of memory, but you can map each choice onto a new array and then use array_count_values():
$result = array_count_values(array_map(function($item) {
return $item['choice'];
}, $data));
Since 5.5 you can simplify it a little more by using array_column():
$result = array_count_values(array_column($data, 'choice'));
You can simplify your code easily if counting is your only goal :
$result = array();
foreach ($data AS $row) {
if (!isset($result[$row['choice']])) {
$result[$row['choice']] = 1;
} else {
$result[$row['choice']]++;
}
}
If you want to count only specific choices, you can change the above code into something like this :
$result = array();
$keys = array('Insulin', 'TZD', 'SGLT-2');
foreach ($data AS $row) {
if (!in_array($row['choice'], $keys)) {
continue;
}
if (!isset($result[$row['choice']])) {
$result[$row['choice']] = 1;
} else {
$result[$row['choice']]++;
}
}
I'm trying to compare 2 Arrays and output the difference in a separate array.
I've made the following line of code to compare 2 Arrays;
$INPUTdifference = array_udiff($userINPUT, $iptablesINPUT, function ($userINPUT, $iptablesINPUT) { return (int) ($userINPUT != $iptablesINPUT); });
When userINPUT contains one row for testing, and iptablesINPUT a few, it works flawlessly.
However, whenever I add a second row in the userINPUT array, it completely stops working. It doesn't even give anything while I print the INPUTdifference anymore
What is wrong here?
EDIT;
The way userINPUT is acquired;
function getIPTablesINPUT() {
/* ------------------------------ */
// INPUT CHAIN
/* ------------------------------ */
$INPUTCOMMAND = popen('/usr/bin/sudo /sbin/iptables -L INPUT -nvx --line-numbers | tail -n +3', 'r');
$INPUTcontent = '';
while (!feof($INPUTCOMMAND)) {
$INPUTcontent .= fread($INPUTCOMMAND, 4096);
}
pclose($INPUTCOMMAND);
$INPUTlines = explode("\n", trim($INPUTcontent));
$INPUTresults = array();
$INPUTcounter = 0;
foreach ($INPUTlines as $line) {
$segments = preg_split('/[\s]+/', $line);
$INPUTArray = array(
'num' => $segments[0],
'pkts' => $segments[1],
'bytes' => $segments[2],
'target' => $segments[3],
'prot' => $segments[4],
'opt' => $segments[5],
'in' => $segments[6],
'out' => $segments[7],
'source' => $segments[8],
'destination' => $segments[9]
);
array_push($INPUTresults, $INPUTArray);
$INPUTcounter++;
}
return $INPUTresults;
}
then, outside of the function
$iptablesINPUT = getIPTablesINPUT();
Then, the way the rules in the data
$dbconnection = pg_connect("host=x port=x dbname=x user=x password=xxxx") or die("Unable to connect to Postgres");
// INPUT table from userDB
$userINPUTresult = pg_query($dbconnection, "SELECT * FROM \"INPUT\"");
if (pg_affected_rows($userINPUTresult) === 1) {
$userINPUTArray = pg_fetch_all($userINPUTresult);
echo "INPUT CHAIN RULES LOADED \n";
} else {
echo ("NO INPUT CHAIN RULES \n");
}
==== VAR DUMPS ====
var_dump $iptablesINPUT
NULL
array(2) {
[0]=>
array(10) {
["num"]=>
string(1) "1"
["pkts"]=>
string(1) "0"
["bytes"]=>
string(1) "0"
["target"]=>
string(4) "DROP"
["prot"]=>
string(3) "all"
["opt"]=>
string(2) "--"
["in"]=>
string(1) "*"
["out"]=>
string(1) "*"
["source"]=>
string(9) "192.0.0.1"
["destination"]=>
string(9) "0.0.0.0/0"
}
[1]=>
array(10) {
["num"]=>
string(1) "2"
["pkts"]=>
string(1) "0"
["bytes"]=>
string(1) "0"
["target"]=>
string(4) "DROP"
["prot"]=>
string(3) "all"
["opt"]=>
string(2) "--"
["in"]=>
string(1) "*"
["out"]=>
string(1) "*"
["source"]=>
string(9) "192.0.0.2"
["destination"]=>
string(9) "0.0.0.0/0"
}
}
var_dump $userINPUT
NULL
Apparentely this is the spot where something goes wrong...
==== EDIT 2 ======
This is the way I extract the arrays from the function out of the scope.
// Slice up userDB arrays for comparing
$userINPUT = $allRules[0];
$userOUTPUT = $allRules[1];
$userFORWARD = $allRules[2];
$userPOSTROUTING = $allRules[3];
$userPREROUTING = $allRules[4];
The array_udiff function returns you the elements which are in the first array and are not in the next arrays.
From array_udiff page:
array array_udiff ( array $array1 , array $array2 [, array $... ], callable $value_compare_func )
Returns an array containing all the values of array1 that are not present in any of the other arguments
Since the value of your first array ($userINPUT in your case) is null then the result of array_udiff will be also null.
Look, after execution of the following code
$a = array(1,2);
$b = array(1);
$c = array_udiff($a, $b, function($a, $b){return (int) $a != $b;});
// $c == array(2) now
the value of $c will be array(2), since the following code
$a = null;
$b = array(1);
$c = array_udiff($a, $b, function($a, $b){return (int) $a != $b;});
// $c == null now
will lead to $c equals null.