php checking if value exist in a 2 level multidimensional array - php

I have this array:
Array
(
[01] => Array
(
[cat_id] => 15
[offset] => 4951
)
[02] => Array
(
[cat_id] => 15
[offset] => 4251
)
[03] => Array
(
[cat_id] => 15
[offset] => 4001
)
[04] => Array
(
[cat_id] => 15
[offset] => 4951
)
[05] => Array
(
[cat_id] => 15
[offset] => 3301
)
)
I have the code to get the key on first level using array_key_exists;
if ((array_key_exists("01", $completed_steps))) {
echo "Found 0!";
}
But I want now to get the cat_id value, how could I do that in a level 2 array?

Use below code, it will find key to n-level depth and search for given key
function multiKeyExists(array $arr, $key) {
// is in base array?
if (array_key_exists($key, $arr)) {
return $arr[$key]['cat_id']; // returned cat_id
}
// check arrays contained in this array
foreach ($arr as $element) {
if (is_array($element)) {
if (multiKeyExists($element, $key)) {
return $element[$key]['cat_id']; // returned cat_id
}
}
}
return false;
}

Try like this:
if ((array_key_exists('cat_id', $completed_steps['01'])) {
echo $completed_steps['01']['cat_id'];
}

You can get particular key-value from it index. See following example:
$check_key = "01";
if ((array_key_exists($check_key, $completed_steps))) {
echo "Found 0! value of cat_id = ".$completed_steps[$check_key]['cat_id'];
}

use the code below
$final_cat_id_array = array();
$key_to_check = 'cat_id';
$catFunc = function($currentArr) use (&$final_cat_id_array, $key_to_check){
if(is_array($currentArr) && array_key_exists($key_to_check, $currentArr)){
$final_cat_id_array[] = $currentArr[$key_to_check];
}
};
$arr = array(
"01" => array("cat_id" => 1, "offset" => true),
"02" => array("cat_id" => 2, "offset" => false),
"03" => array("cat_id" => 3, "offset" => true),
);
array_walk($arr, $catFunc);
print_r($final_cat_id_array);
the final $final_cat_id_array will have all the cat_id.

Related

unset array key and rearrange the key

This is how my array looks like :
Array
(
[0] => Array
(
[unit] => 10
[harga] => 15000
)
[1] => Array
(
[unit] => 7
[harga] => 10000
)
[2] => Array
(
[unit] => 12
[harga] => 123123
)
)
I want to unset the 0 key array when the unit is 0 and rearrange the key so the 1 key will replace the 0.
This is how I do it :
$jumlah_penjualan = $data - > unit;
while ($jumlah_penjualan > 0) {
$persediaan_pertama = $persediaan[0]['unit'];
$harga_persediaan = $persediaan[0]['harga'];
if ($persediaan_pertama < $jumlah_penjualan) {
$dijual = $persediaan_pertama;
$penjualan[] = array(
'unit' => $dijual,
'harga' => $harga_persediaan,
'total' => $dijual * $harga_persediaan);
$persediaan[0]['unit'] = $persediaan[0]['unit'] - $dijual;
} else {
$dijual = $jumlah_penjualan;
$penjualan[] = array(
'unit' => $dijual,
'harga' => $harga_persediaan,
'total' => $dijual * $harga_persediaan);
$persediaan[0]['unit'] = $persediaan[0]['unit'] - $dijual;
}
if ($persediaan[0]['unit'] == 0) {
unset($persediaan[0]);
$persediaan = array_values($persediaan);
}
$jumlah_penjualan = $jumlah_penjualan - $dijual;
}
But the result looks like it continues looping before rearranging the array.
This is how the array should look like after unset:
Array(
[0] => Array
(
[unit] => 9
[harga] => 123123
)
)
If you want to remove the first elements until the unit is not 0, you can
$arr = array
(
array
(
"unit" => 0,
"harga" => 15000
),
array
(
"unit" => 0,
"harga" => 10000
),
array
(
"unit" => 12,
"harga" => 123123
)
);
while( $arr[0]["unit"] == 0 ) { //Loop until $arr[0]["unit"] is not 0
unset($arr[0]); //Remove $arr[0] since unit is 0
$arr = array_values($arr); //Make Make element 1 to element 0
}
echo "<pre>";
print_r( $arr );
echo "</pre>";
This will result to:
Array
(
[0] => Array
(
[unit] => 12
[harga] => 123123
)
)
To remove the first element of an array and reindex the elements, use array_shift. First, check that the number of units are zero, then remove the first element if that's the case.
if ($arr[0]['unit'] == 0) {
array_shift($arr);
}
Since it's impossible to say what your other variables even mean because of the language, you probably want to move this outside of your while loop, so that the first element is only removed after you've processed the array.

Group and merge subarray data based on one column value

I have an array in PHP code below, and I want to convert this array to be grouped by data value. It's always hard to simplify arrays.
Original array:
Array
(
[0] => Array
(
[date] => 2017-08-22
[AAA] => 1231
)
[1] => Array
(
[date] => 2017-08-21
[AAA] => 1172
)
[2] => Array
(
[date] => 2017-08-20
[AAA] => 1125
)
[3] => Array
(
[date] => 2017-08-21
[BBB] => 251
)
[4] => Array
(
[date] => 2017-08-20
[BBB] => 21773
)
[5] => Array
(
[date] => 2017-08-22
[CCC] => 3750
)
[6] => Array
(
[date] => 2017-08-20
[CCC] => 321750
)
)
Below is my desired array:
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
It is also ok to have empty null value if the data doesn't exist. [BBB] => NULL for 2017-08-22.
Can anybody help? Thanks in advance...
A simple loop should do this..
$group = [];
foreach ($data as $item) {
if (!isset($group[$item['date']])) {
$group[$item['date']] = [];
}
foreach ($item as $key => $value) {
if ($key == 'date') continue;
$group[$item['date']][$key] = $value;
}
}
Here : this should do the work.
$dst_array = array();
foreach ($array as $outerval) {
foreach ($outerval as $key => $innerval) {
if ($key != 'date') {
$dst_array[$outerval['date']][$key] = $innerval;
}
}
}
It iterates through the array and then through the entries in each subarray. Any any that is not a date is assigned in the destination array in the subarray corresponding to its date and with its own current key.
I definitely wouldn't recommend any techniques that involve more than one loop -- this process can certainly be performed in a single loop.
If you like language construct iteration, use a foreach() loop: (Demo)
$result = [];
foreach ($array as $row) {
$date = $row['date'];
unset($row['date']);
$result[$date] = array_merge($result[$date] ?? [], $row);
}
var_export($result);
If you like to use functional programming and fewer global variables, use array_reduce(): (Demo)
var_export(
array_reduce(
$array,
function($accumulator, $row) {
$date = $row['date'];
unset($row['date']);
$accumulator[$date] = array_merge($accumulator[$date] ?? [], $row);
return $accumulator;
},
[]
)
);
These techniques unconditionally push data into the subarray with the key based on the date column value.
The above technique will work consistently even if the order of your subarray elements changes.
The ?? (null coalescing operator) is to ensure that array_merge() always has an array in the first parameter -- if processing the first occurrence of a given date, you simply merge the current iteration's data (what's left of it after unset() removes the date element) with an empty array.
I believe this solution will work for you:
<?php
$array = Array
(
0 => Array
(
'date' => '2017-08-22',
'AAA' => '1231',
),
1 => Array
(
'date' => '2017-08-21',
'AAA' => '1172',
),
2 => Array
(
'date' => '2017-08-20',
'AAA' => '1125'
),
3 => Array
(
'date' => '2017-08-21',
'BBB' => '251'
),
4 => Array
(
'date' => '2017-08-20',
'BBB' => '21773',
),
5 => Array
(
'date' => '2017-08-22',
'CCC' => '3750'
),
6 => Array
(
'date' => '2017-08-20',
'CCC' => '321750'
)
);
echo '<pre>';
$array1 = array('AAA' => null, 'BBB' => null, 'CCC' => null);
$array2 = array();
array_walk($array, function ($v) use (&$array2, $array1) {
$a = $v['date'];
if (!isset($array2[$a])) {
$array2[$a] = $array1;
}
unset($v['date']);
$array2[$a] = array_merge($array2[$a], $v);
});
print_r($array2);
Output
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[BBB] =>
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
[CCC] =>
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
check output at: https://3v4l.org/NvLB8
Another approach (quick & dirty) making use of an arrays internal pointer:
$newArray = [];
foreach ($array as $childArray) {
$date = current($childArray);
$value = next($childArray); // this advances the internal pointer..
$key = key($childArray); // ..so that you get the correct key here
$newArray[$date][$key] = $value;
}
This of course only works with the given array structure.
Another perfect usage example for the PHP function array_reduce():
// The input array
$input = array(
0 => array(
'date' => '2017-08-22',
'AAA' => '1231',
),
// The rest of your array here...
);
$output = array_reduce(
$input,
function (array $carry, array $item) {
// Extract the date into a local variable for readability and speed
// It is used several times below
$date = $item['date'];
// Initialize the group for this date if it doesn't exist
if (! array_key_exists($date, $carry)) {
$carry[$date] = array();
}
// Remove the date from the item...
// ...and merge the rest into the group of this date
unset($item['date']);
$carry[$date] = array_merge($carry[$date], $item);
// Return the partial result
return $carry;
},
array()
);
The question is not clear. What is the expected result if one key (AAA f.e) is present on two or more dates? This answer keeps only the last value associated with it.

Sort array values based on parent/child relationship

I am trying to sort an array to ensure that the parent of any item always exists before it in the array. For example:
Array
(
[0] => Array
(
[0] => 207306
[1] => Bob
[2] =>
)
[1] => Array
(
[0] => 199730
[1] => Sam
[2] => 199714
)
[2] => Array
(
[0] => 199728
[1] => Simon
[2] => 207306
)
[3] => Array
(
[0] => 199714
[1] => John
[2] => 207306
)
[4] => Array
(
[0] => 199716
[1] => Tom
[2] => 199718
)
[5] => Array
(
[0] => 199718
[1] => Phillip
[2] => 207306
)
[6] => Array
(
[0] => 199720
[1] => James
[2] => 207306
)
)
In the above array this "fails" as [1][2] (Sam) does not yet exist and nor does [4][2] (Tom).
The correct output would be as, in this case, as both Sam and Tom's parents already exist before they appear in the array:
Array
(
[0] => Array
(
[0] => 207306
[1] => Bob
[2] =>
)
[1] => Array
(
[0] => 199714
[1] => John
[2] => 207306
)
[2] => Array
(
[0] => 199730
[1] => Sam
[2] => 199714
)
[3] => Array
(
[0] => 199728
[1] => Simon
[2] => 207306
)
[4] => Array
(
[0] => 199718
[1] => Phillip
[2] => 207306
)
[5] => Array
(
[0] => 199716
[1] => Tom
[2] => 199718
)
[6] => Array
(
[0] => 199720
[1] => James
[2] => 207306
)
)
I found an answer https://stackoverflow.com/a/12961400/1278201 which was very close but it only seems to go one level deep (i.e. there is only ever one parent) whereas in my case there could be 1 or 10 levels deep in the hierarchy.
How do I sort the array so no value can appear unless its parent already exists before it?
This will trivially order the array (in O(n)) putting first all those with no parent, then these whose parent is already in the array, iteratively, until there's no children having the current element as parent.
# map the children by parent
$parents = ['' => []];
foreach ($array as $val) {
$parents[$val[2]][] = $val;
}
# start with those with no parent
$sorted = $parents[''];
# add the children the current nodes are parent of until the array is empty
foreach ($sorted as &$val) {
if (isset($parents[$val[0]])) {
foreach ($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
This code requires PHP 7, it may not work in some cases under PHP 5. - for PHP 5 compatibility you will have to swap the foreach ($sorted as &$val) with for ($val = reset($sorted); $val; $val = next($sorted)):
# a bit slower loop which works in all versions
for ($val = reset($sorted); $val; $val = next($sorted)) {
if (isset($parents[$val[0]])) {
foreach ($parents[$val[0]] as $next) {
$sorted[] = $next;
}
}
}
Live demo: https://3v4l.org/Uk6Gs
I have two different version for you.
a) Using a "walk the tree" approach with recursion and references to minimize memory consumption
$data = [
[207306,'Bob',''], [199730,'Sam',199714],
[199728,'Simon',207306], [199714,'John',207306],
[199716, 'Tom',199718], [199718,'Phillip',207306],
[199720,'James',207306]
];
$list = [];
generateList($data, '', $list);
var_dump($list);
function generateList($data, $id, &$list) {
foreach($data as $d) {
if($d[2] == $id) {
$list[] = $d; // Child found, add it to list
generateList($data, $d[0], $list); // Now search for childs of this child
}
}
}
b) Using phps built in uusort()function (seems only to work up to php 5.x and not with php7+)
$data = [
[207306,'Bob',''], [199730,'Sam',199714],
[199728,'Simon',207306], [199714,'John',207306],
[199716, 'Tom',199718], [199718,'Phillip',207306],
[199720,'James',207306]
];
usort($data, 'cmp');
var_dump($data);
function cmp($a, $b) {
if($a[2] == '' || $a[0] == $b[2]) return -1; //$a is root element or $b is child of $a
if($b[2] == '' || $b[0] == $a[2]) return 1; //$b is root element or $a is child of $b
return 0; // both elements have no direct relation
}
I checked this works in PHP 5.6 and PHP 7
Sample array:
$array = Array(0 => Array(
0 => 207306,
1 => 'Bob',
2 => '',
),
1 => Array
(
0 => 199730,
1 => 'Sam',
2 => 199714,
),
2 => Array
(
0 => 199728,
1 => 'Simon',
2 => 207306,
),
3 => Array
(
0 => 199714,
1 => 'John',
2 => 207306,
),
4 => Array
(
0 => 199716,
1 => 'Tom',
2 => 199718,
),
5 => Array
(
0 => 199718,
1 => 'Phillip',
2 => 207306,
),
6 => Array
(
0 => 199720,
1 => 'James',
2 => 207306,
),
);
echo "<pre>";
$emp = array();
//form the array with parent and child
foreach ($array as $val) {
$manager = ($val[2] == '') ? 0 : $val[2];
$exist = array_search_key($val[2], $emp);
if ($exist)
$emp[$exist[0]][$val[0]] = $val;
else
//print_R(array_search_key(199714,$emp));
$emp[$manager][$val[0]] = $val;
}
$u_emp = $emp[0];
unset($emp[0]);
//associate the correct child/emp after the manager
foreach ($emp as $k => $val) {
$exist = array_search_key($k, $u_emp);
$pos = array_search($k, array_keys($u_emp));
$u_emp = array_slice($u_emp, 0, $pos+1, true) +
$val +
array_slice($u_emp, $pos-1, count($u_emp) - 1, true);
}
print_R($u_emp); //print the final result
// key search function from the array
function array_search_key($needle_key, $array, $parent = array())
{
foreach ($array AS $key => $value) {
$parent = array();
if ($key == $needle_key)
return $parent;
if (is_array($value)) {
array_push($parent, $key);
if (($result = array_search_key($needle_key, $value, $parent)) !== false)
return $parent;
}
}
return false;
}
Find the below code that might be helpful.So, your output is stored in $sortedarray.
$a=array(array(207306,'Bob',''),
array (199730,'Sam',199714),
array(199728,'Simon',207306),
array(199714,'John',207306),
array(199716,'Tom',199718),
array(199718,'Phillip',207306),
array(199720,'James',207306));
$sortedarray=$a;
foreach($a as $key=>$value){
$checkvalue=$value[2];
$checkkey=$key;
foreach($a as $key2=>$value2){
if($key<$key2){
if ($value2[0]===$checkvalue){
$sortedarray[$key]=$value2;
$sortedarray[$key2]=$value;
}else{
}
}
}
}
print_r($sortedarray);
What about this approach:
Create an empty array result.
Loop over your array and only take the items out of it where [2] is empty and insert them into result.
When this Loop is done you use a foreach-Loop inside a while-loop. With the foreach-Loop you take every item out of your array where [2] is already part of result. And you do this as long as your array contains anything.
$result = array();
$result[''] = 'root';
while(!empty($yourArray)){
foreach($yourArray as $i=>$value){
if(isset($result[$value[2]])){
// use the next line only to show old order
$value['oldIndex'] = $i;
$result[$value[0]] = $value;
unset($yourArray[$i]);
}
}
}
unset($result['']);
PS: You may run into trouble by removing parts of an array while walking over it. If you do so ... try to solve this :)
PPS: Think about a break condition if your array have an unsolved loop or a child without an parent.
you can use your array in variable $arr and use this code it will give you required output.
function check($a, $b) {
return ($a[0] == $b[2]) ? -1 : 1;
}
uasort($arr, 'check');
echo '<pre>';
print_r(array_values($arr));
echo '</pre>';

2 arrays match data into 1 array with PHP

I have 2 array's, first array have for example ItemID of my item, second array have description about my item. I want to match data into 1 array.
It looks like:
[rgInventory] => Array
(
[1234567890] => Array
(
[id] => 1234567890
[classid] => 123456789
[instanceid] => 987654321
[amount] => 1
[pos] => 1
)
)
[rgDescriptions] => Array
(
[192837465_918273645] => Array
(
[appid] => 730
[name] => Something
)
)
Items in arrays don't have the same value like ID, but they are in the same order so:
Description for the first item in rgInventory is in the first array inside rgDescriptions.
What should I do to match for example id from rgInventory with name from rgDescriptions in the same array for example $backpack = array();?
Regards for you.
Try this:
<?php
$array1 = array('rgInventory' =>
array(
'1234567890' => array(
'id' => 1234567890,
'classid' => 123456789,
'instanceid' => 987654321,
'amount' => 1,
'pos' => 1
)
)
);
$array2 = array(
'rgDescriptions' => array(
'192837465_918273645' => array(
'appid' => 730, 'name' => 'Something')
)
);
Create new function to combine the two arrays into one array:
function array_sum_recursive($data1, $data2) {
if (!is_array($data1) && !is_array($data2)) {
return $data1 + $data2;
}
// deepest array gets precedence
if (!is_array($data2)) {
return $data1;
}
if (!is_array($data1)) {
return $data2;
}
//merge and remove duplicates
$keys = array_unique(array_merge(array_keys($data1), array_keys($data2)));
foreach ($keys as $key) {
if (isset($data1[$key]) && isset($data2[$key])) {
$result[$key] = array_sum_recursive($data1[$key], $data2[$key]);
} else if (isset($data1[$key])) {
$result[$key] = $data1[$key];
} else {
$result[$key] = $data2[$key];
}
}
if(empty($result)){
echo "no result";
die();
}else{
return $result;
}
}
Put the two array in one array $newarray:
$newonearray = array_sum_recursive($array1, $array2);
echo '<pre>';
print_r($newonearray);
?>
And you will get this:
Array
(
[rgInventory] => Array
(
[1234567890] => Array
(
[id] => 1234567890
[classid] => 123456789
[instanceid] => 987654321
[amount] => 1
[pos] => 1
)
)
[rgDescriptions] => Array
(
[192837465_918273645] => Array
(
[appid] => 730
[name] => Something
)
)
)
Hope this may help.
You can use function each to get each element of both arrays, then merge its with array_merge and save this new item to backup array.
Try something like this
<?php
$rgInventory = ['firstInv' => ['invId' => 1], 'secondInv' => ['invId' => 2]];
$rgDescriptions = ['firstDesc' => ['descId' => 1], 'secondDesc' => ['descId' => 2]];
if (count($rgInventory) && count($rgInventory) == count($rgDescriptions)) {
$backpack = [];
while($inventory = each($rgInventory)) {
$description = each($rgDescriptions);
$item = array_merge($inventory['value'], $description['value']);
$backpack[] = $item;
}
var_dump($backpack);
}
Output will be:
array(2) {
[0]=>
array(2) {
["invId"]=>
int(1)
["descId"]=>
int(1)
}
[1]=>
array(2) {
["invId"]=>
int(2)
["descId"]=>
int(2)
}
}

Pushing a sub array into the same array

I am trying to put content of one array into the same array. Here I have an array $mclass with values such as
Array
(
[0] => stdClass Object
(
[room_id] => 1,3,5
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
)
You can see I have room_id index with 1,3,5 value. Now, I want to explode the room_id and get duplicate of same array index data with change of room_id and push into the array. and finally delete the current array index such as [0]. Here I want the final result as.
Array
(
[0] => stdClass Object
(
[room_id] => 1
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
[1] => stdClass Object
(
[room_id] => 3
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
[2] => stdClass Object
(
[room_id] => 5
[day] => 1
[class_teacher] => TEA-2014-2
[final_exam_date] => 2015-09-21
)
)
Here is my code for the same:
if(count($mclass)>0)
{
foreach($mclass as $mclasskey=>$mclass_row)
{
/* Room ID Calculation */
if(isset($mclass[$mclasskey]))
{
$temp_room_id = explode(',',$mclass_row->room_id);
if(count($temp_room_id)>1)
{
foreach($temp_room_id as $trkey=>$tr)
{
if(!in_array($temp_room_id[$trkey], $morning_class_semester))
{
array_push($morning_class_semester,$temp_room_id[$trkey]);
}
}
if(count($morning_class_semester)>0)
{
foreach($morning_class_semester as $mcskey=>$mcs)
{
$index_count = count($new_test);
$test[$index_count] = $mclass[$mclasskey];
$test[$index_count]->room_id = $morning_class_semester[$mcskey];
array_push($new_test,$test[$index_count]);
}
unset($mclass[$mclasskey]);
}
}
}
}
}
The code below does what you're looking for using only arrays. So you'll have to change the array access operators to -> since you're accessing an object. I'd do so, but it would break the example, so I'll leave that up to you.
Code Explained:
Loop through array selecting each subarray (object in your case), explode on the $item('room_id') ... ($item->room_id in your case) ... and create sub arrays, via loop, from that using the data from the original using each key. Remove the original item (which has the combined room_ids) and combine the placeholder and original array.
<?php
//Establish some data to work with
$array = array(
array(
"room_id" => "1,3,5",
"day" => 1,
"class_teacher" => "TEA-2014-2",
"final_exam_date" => "2015-09-21",
));
foreach ($array as $key => $item) {
$placeholder = array();
$ids = explode(',',$item['room_id']);
if (count($ids) > 1) {
foreach ($ids as $id) {
$push = array(
'room_id' => $id,
'day' => $item['day'],
'class_teacher' => $item['class_teacher'],
'final_exam_date' => $item['final_exam_date']
);
array_push($placeholder, $push);
}
$array = array_merge($array, $placeholder);
unset($array[$key]);
}
}
var_dump($array);
?>

Categories