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.
Related
I have arrays, I don't know how to fix
I already try array_push, array_combine, array_merge, but still nothing.
$distance = array(3) {
[0]=>
float(2.2)
[1]=>
float(1.1)
[2]=>
float(3.9)
}
$getID = array(3) {
[0]=>
string(1) "B"
[1]=>
string(1) "C"
[2]=>
string(1) "F"
}
I want to
array(3) {
[0]=> ["B", 2.2]
[1]=> ["C", 1.1]
[2]=> ["F", 3.9]
}
this is my code
function mergeArray($distance, $getID)
{
$mergeArray = array();
for ($i = 0; $i < count($distance); $i++) {
$mergeArray[] = array_splice($getID, $distance[$i]);
}
return $mergeArray;
}
Edited
help me please thx
You don't need "array_combine()", "array_slice()" or similar. Just iterate through the data and create a new one:
$a = [2.2, 1.1, 3.9];
$b = ["B", "C", "F"];
$new = [];
foreach ($a as $index => $value) {
$new[] = [
$b[$index], // Fetch the value with the same index from the other array
$value
];
}
Demo: https://3v4l.org/oseSV
You can use array_map to iterate over two arrays simultaneously and produce a new array:
$distance = array(3) {
[0]=>
float(2.2)
[1]=>
float(1.1)
[2]=>
float(3.9)
}
$getID = array(3) {
[0]=>
string(1) "B"
[1]=>
string(1) "C"
[2]=>
string(1) "F"
}
$output = array_map(function ($d, $id) {
return [$id, $d];
}, $distance, $getID);
Note that this code assumes that both arrays have the same length.
Offtopic:
A little advice about your code: always name your variable with something that allows you to know what's inside it, using correct plural too:
Your $distance variable contains an array off distances, so it nsme should be in plural.
Your $getID is not a function, so it should not be called get, but just $Ids instead.
$distance = [ 2.2, 1.1, 3.9 ];
$getID = [ "B", "C", "F" ];
$result = array_map(fn(string $id, float $distance) => [ $id, $distance ], $getID, $distance);
print_r($result);
For your current code to work you have to:
pass both elements to array_splice function as an array
pass the offset of where the function need to replace the value
as well as the number of how many elements should be removed
You should not reassign $mergeArray because array_splice work with pointer
Checkout the docs for more!
function mergeArray($distance, $getID)
{
$mergeArray = [];
for ($i = 0; $i < count($distance); $i++) {
array_splice($mergeArray,$i,1, [[
$distance[$i],
$getID[$i]
]]);
}
return $mergeArray;
}
however a better approach is to do as in M. Eriksson's ansewar.
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
I have the variable $request. If i do vardump($request), I get the output of:
array(7) {
["controller"]=> string(5) "index"
["action"]=> string(5)"index"
["module"]=> string(7) "default"
[2]=> array(8) {
["g_goal_list_id"]=> string(3) "127"
["textgoal"]=> string(9) "eats food"
["task_0"]=> string(1) "0"
["value_0"]=> string(5) "pukes"
["task_1"]=> string(1) "0"
["value_1"]=> string(0) ""
["task_2"]=> string(1) "0"
["value_2"]=> string(0) ""
}
[3]=> array(10) {
["g_goal_list_id"]=> string(3) "128"
["textgoal"]=> string(9) "goes home"
["task_0"]=> string(1) "0"
["value_0"]=> string(20) "but never comes back"
["task_1"]=> string(1) "0"
["value_1"]=> string(14) "stays home now"
["task_2"]=> string(1) "0"
["value_2"]=> string(0) ""
["task_3"]=> string(1) "0"
["value_3"]=> string(0) ""
}
["submit"]=> string(4) "Save"
["task"]=> string(1) "5"
}
which is all correct. However, I'm trying to use a foreach statment to grab values from the $request array and put them into a data array, and then submit that to the mysql db...
foreach($request as $currentrow){
//skips row if the field is empty
if(strlen($currentrow['value']) < 1)//need to make sure I've defined $currentrow['value']
continue;//skips row with empty field
//I only need to grab the value/list_id/account_id from the form
$data = array('value' => $currentrow['value'],
'g_goal_list_id' => $currentrow['g_goal_list_id'],
'account_id' => g_getAccountId(),
);
var_dump($data);
However, when I var_dump($data); my output looks like this:
array(3) { ["value"]=> string(1) "i" ["g_goal_list_id"]=> string(1) "i" ["account_id"]=> string(1) "1" }
array(3) { ["value"]=> string(1) "S" ["g_goal_list_id"]=> string(1) "S" ["account_id"]=> string(1) "1" }
array(3) { ["value"]=> string(1) "5" ["g_goal_list_id"]=> string(1) "5" ["account_id"]=> string(1) "1" }
The only thing that is correct in that var_dump($data) is the ["account_id"]
I'm thinking that my loop is incorrect, and I'm pretty bad with loops. Sooooo yeah, hopefully I included enough information. Thank you.
What you need is something like this:
foreach($request as $k=>$currentrow)
{
$hit = false;
$data = array();
// Only look for sub-arrays
if(is_array($currentrow))
{
foreach($currentrow as $k2=>$v2)
{
$explode = explode('_', $k2);
if($explode[0] === 'value') //need to make sure I've defined $currentrow['value'] regardless of suffix
{
$hit = true;
$data = array(
'value' => $v2,
'g_goal_list_id' => $currentrow[$k]['g_goal_list_id'],
'account_id' => g_getAccountId(),
);
continue;
}
}
}
if($hit === false)
{
continue;
}
var_dump($data);
}
This element: $currentrow['values'] does not exist (check your logs, you should see notices). Neither does $currentrow['g_goal_list_id'].
You loop through an array with all different elements, the first being a string, with value index. When you then take that string and subscribe that with values, it throws a warning, but then takes the first element.
To clarify, a some CLI code:
php > $a="abcd";
php > echo $a["foo"];
PHP Warning: Illegal string offset 'foo' in php shell code on line 1
a
If you want to loop over keys and values, do like this:
foreach($request as $key=>$value) {
}
That being said, I think a loop is not what you want, you do not have straighforward table-like data.
Huge thanks to #MonkeyZeus. I kept on getting an array that had the proper keys but all the values were null. Turns out I just needed to put my var_dump($data) inside of my loop, because when it was on the outside it was returning only the last array it looped thorough. On my form the last values it loops through were empty fields, that are meant for the user to add input. Also, I had to change 'g_goal_list_id' => $currentrow[$k]['g_goal_list_id'] to just 'g_goal_list_id' => $currentrow['g_goal_list_id']
foreach ($request as $k=> $currentrow) {
$hit = false;
$data = array();
if(is_array($currentrow)){
foreach ($currentrow as $k2 => $v2) {
$explode = explode('_', $k2); //blows off the suffix of the $key
//var_dump($explode);
//$explode=substr($explode,2);
//echo $k2;
//echo '******';
//echo $v2;
echo $explode[0];
echo '/';
if($explode[0] == 'value'){
//echo "[" . $currentrow['g_goal_list_id'] . "]";
$hit = true;
$data = array(
'value' => $v2,
'g_goal_list_id' => $currentrow['g_goal_list_id'],
'account_id'=> g_getAccountId(),
);
continue;
}
var_dump($data);
}
}
if ($hit === false){
continue;
}
break;
}
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']]++;
}
}