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));
Related
I need some more help regarding PHP Arrays and the issue I am having. I have an array like this: -
array(2) {
[0]=>
array(2) {
[0]=>
array(2) {
["count"]=>
string(3) "100"
["id"]=>
int(46)
}
[1]=>
array(2) {
["count"]=>
string(3) "300"
["id"]=>
int(53)
}
}
[1]=>
array(1) {
[0]=>
array(2) {
["count"]=>
string(3) "200"
["id"]=>
int(46)
}
}
}
However, I would like it to look more like this as array: -
array(2) {
[0]=>
array(2) {
["count"]=>
string(3) "300" <--- This has been added from Array 1 and 2
["id"]=>
int(46)
}
[1]=>
array(2) {
["count"]=>
string(3) "300"
["id"]=>
int(53)
}
}
Basically if the same id is in both areas I want the count number to be added to each other but if it's not then it needs to just be left alone and included in the array.
I have used a number of array functions such as array_merge and array_push but I am running out of ideas of how this could work. I have also started working on a foreach with if statements but I just got myself completely confused. I just need a second pair of eyes to look at the issue and see howe it can be done.
Thanks again everyone.
Should work with something like this:
$idToCountArray = array(); //temporary array to store id => countSum
array_walk_recursive($inputArray, function($value,$key) { //walk each array in data structure
if(isset(value['id']) && isset($value['count'])) {
//we have found an entry with id and count:
if(!isset($idToCountArray[$value['id']])) {
//first count for id => create initial count
$idToCountArray[$value['id']] = intval($value['count']);
} else {
//n'th count for id => add count to sum
$idToCountArray[$value['id']] += intval($value['count']);
}
}
});
//build final structure:
$result = array();
foreach($idToCountArray as $id => $countSum) {
$result[] = array('id' => $id, 'count' => ''.$countSum);
}
Please note that I have not testet the code and there is probably a more elegant/performant solution.
You could use something like this:
$end_array = array();
function build_end_array($item, $key){
global $end_array;
if (is_array($item)){
if( isset($item["id"])){
if(isset($end_array[$item["id"]]))
$end_array[$item["id"]] = $end_array[$item["id"]] + $item["count"]*1;
else
$end_array[$item["id"]] = $item["count"]*1;
}
else {
array_walk($item, 'build_end_array');
}
}
}
array_walk($start_array, 'build_end_array');
Here is a fiddle.
Thank you ever so much everyone. I actually worked it by doing this: -
$fullArray = array_merge($live, $archive);
$array = array();
foreach($fullArray as $key=>$value) {
$id = $value['id'];
$array[$id][] = $value['count'];
}
$result = array();
foreach($array as $key=>$value) {
$result[] = array('id' => $key, 'count' => array_sum($value));
}
return $result;
Really struggling with this. I have a multidimensional array n levels deep. Each 'array level' has information I need to check (category) and also check if it contains any arrays.
I want to return the category ids of all the arrays which have a category and do not contain an array (i.e. the leaves). I can echo output properly, but I am at a loss as how to return the ids in an array (without referencing)
I have tried RecursiveIteratorIterator::LEAVES_ONLY and RecursiveArrayIterator but I don't think they work in my case? (Maybe I am overlooking something)
$array
array(2) {
["1"]=>
string(5) "stuff"
["2"]=>
array(2) {
["category"]=>
string(1) "0"
["1"]=>
array(3) {
[0]=>
array(3) {
["category"]=>
string(1) "1"
["1"]=>
string(5) "stuff"
["2"]=>
string(5) "stuff"
}
[1]=>
array(5) {
["category"]=>
string(1) "2"
["1"]=>
string(5) "stuff"
["2"]=>
string(5) "stuff"
}
[1]=>
array(5) {
["1"]=>
string(5) "stuff"
["32"]=>
string(5) "stuff"
}
}
}
}
My function
public function recurs($array, $cats = [])
{
$array_cat = '';
$has_array = false;
// Check if an id exists in the array
if (array_key_exists('category', $array)) {
$array_cat = $array['category'];
}
// Check if an array exists within the array
foreach ($array as $key => $value) {
if (is_array($value)) {
$has_array = true;
$this->recurs($value, $cats);
}
}
// If a leaf array
if (!$has_array && is_numeric($array_cat)) {
echo "echoing the category here works fine: " . $array_cat . "\n";
return $array_cat;
}
}
Calling it
$cats_array = $this->recurse($array)
Output echoed
echoing the category here works fine: 1
echoing the category here works fine: 2
How do I return the ids in an array to use in the $cats_array variable?
EDIT: The output should match the echo, so I should get an array containing (1, 2) since they are the only arrays with categories and no arrays within them
array(2){
[0]=>
int(1) "1"
[1]=>
int(1) "2"
}
If I understood you correctly this function will do the job:
function getCategories(array $data)
{
if ($subArrays = array_filter($data, 'is_array')) {
return array_reduce(array_map('getCategories', $subArrays), 'array_merge', array());
};
return array_key_exists('category', $data) ? array($data['category']) : array();
}
If the array contains any sub-arrays they will be returned by array_filter and you will enter the if statement. array_map will apply the function recursively to the sub-arrays and array_reduce will merge the results.
If the array doesn't contain any sub-arrays you will not enter the if statement and the function will return an array with the category if it is present.
Note that you might need to use array_unique to return unique categories.
Also for small performance optimization instead of array_key_exists you can use isset($array[$key]) || array_key_exists($key, $array).
Update
If you want to update your function to make it work you have to recursively collect and merge the sub results. In the following example I introduced a new variable for this:
public function recurs($array, $cats = [])
{
$result = [];
$array_cat = '';
$has_array = false;
// Check if an id exists in the array
if (array_key_exists('category', $array)) {
$array_cat = $array['category'];
}
// Check if an array exists within the array
foreach ($array as $key => $value) {
if (is_array($value)) {
$has_array = true;
$result = array_merge($result, $this->recurs($value, $cats));
}
}
// If a leaf array
if (!$has_array && is_numeric($array_cat)) {
echo "echoing the category here works fine: " . $array_cat . "\n";
return [$array_cat];
}
return $result;
}
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.
I have an array that groups different items by item type. I am grouping the result by category_id field. What I want is the output to be
item1 = 3
item2 = 2
My array looks like this if I do a var_dump()
array(2) {
["item1"]=>
array(3) {
[0]=>
string(1) "3"
[2]=>
string(1) "5"
[4]=>
string(1) "7"
}
["item2"]=>
array(2) {
[1]=>
string(1) "4"
[3]=>
string(1) "6"
}
}
Here is the code I am using:
$items = Item::where('order_id','=',$payload["orderId"])->get();
$itemsGrouped = [];
$count = 0;
foreach($items as $item){
$itemsGrouped[$item->category_id][$count] = $item->id;
$count++;
}
foreach($itemsGrouped as $grp){
echo key($itemsGrouped).'='.count($grp).'<br>';
};
And here is what I am currently getting. The count is working but not the $itemsGrouped key. It is duplicated.
item2=3<br>item2=2<br>
Change your code as below
foreach($itemsGrouped as $key => $grp){
echo $key.'='.count($grp).'<br>';
};
In order to use key() function, you need to traverse the array using next/current function
foreach($itemsGrouped as $key => $grp){
echo $key.'='.count($grp).'<br>';
};
key() function returns the current element's key, which is defined by an array's internal pointer. Obviously it always points to the last element.
$myarray = "Your array";
$count = array(); // create an empty array
foreach($myarray as $arr) {
foreach($arr as $a) {
$key = array_keys($a);
$count[$key[0]]++;
}
}
print_r($count);