array flip collision issue - php

Is there a function/method I am unaware of that avoids removal of like keys when the array is flipped. Example below:
Original array:
Array ( [last_modified] => input [published] => input [project_content] => textarea )
With array flip (collision of keys):
Array ( [input] => published [textarea] => project_content )

If you want to preserve your keys, you can have a two dimensional array:
<?php
$arr = array ( 'last_modified' => 'input', 'published' => 'input', 'project_content' => 'textarea' );
$result = array();
foreach($arr as $k => $v) {
if (array_key_exists($v, $result)) {
$result[$v][] = $k;
} else {
$result[$v] = array($k);
}
}
print_r($result);
?>
This will print out:
Array
(
[input] => Array
(
[0] => last_modified
[1] => published
)
[textarea] => Array
(
[0] => project_content
)
)

There is a dead simple way to get all the keys in the array that have the value "input" using the standard function array_keys:
$keys = array_keys($array, "input");
That is all; see it in action.

Related

php - check multidimensional array for values that exists in more than 1 subarray

Following simplified multidimensional array given:
$input = Array
(
[arr1] => Array
(
[0] => JAN2016
[1] => MAI2013
[2] => JUN2014
}
[arr2] => Array
(
[0] => APR2016
[1] => DEC2013
[2] => JUN2014
}
[arr3] => Array
(
[0] => JAN2016
[1] => MAI2020
[2] => JUN2022
}
)
I want to check for elements, that exists in more than 1 subarray. An ideal output would be:
$output = Array
(
[JUN2014] => Array
(
[0] => arr1
[1] => arr2
)
[JAN2016] => Array
(
[0] => arr1
[1] => arr3
)
)
I'm currently stucked in a nested foreach because i need to look all silblings of the outer foreach and don't know how to accomplish that.
foreach($input as $k=>$values)
{
foreach($values as $value)
{
//check if value exists in array k+1....n
//if true, safe to output.
}
}
You are almost all the way there
$new = [];
foreach($input as $k=>$values) {
foreach($values as $value) {
$new[$value][] = $k;
}
}
The $new array should look just as you want it
Extended solution which filters subarrays:
$newArray = [];
foreach($input as $k=>$values)
{
foreach($values as $value)
{
$newArray[$value][] = $k;
}
}
print_r(array_filter(
$newArray,
function($v) { return 1 < count($v); }
));
Sample fiddle here.

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.

Simplify a multidimensional array in PHP

I've received and XML, converted it into an array for usage.
The XML comes in unpredictable multi dimension when I convert it into array.
Had been looking around but could not find a suitable solution.
An alternative is to simplify the converted array.
I've converted an XML to array in PHP, and the result looked like this:
Array
(
[GetMLCBRes] => Array
(
[0] => Array
(
[Ord] => Array
(
[0] => Array
(
[OrdId] => Array
(
[0] => DP Order ID
)
)
)
[ReqInf] => Array
(
[0] => Array
(
[ReqDat] => Array
(
[0] => Date of Request
)
)
)
[Res] => Array
(
[0] => PDF Report
)
)
)
)
May I know how to drop the index like [0] but remain the assoc keys like [Ord], [OrdId], [ReqInf] and [Res], etc.
How to convert it to become like this?
Array
(
[GetMLCBRes] => Array
(
[Ord] => Array
(
[OrdId] => DP Order ID
)
[ReqInf] => Array
(
[ReqDat] => Date of Request
)
[Res] => PDF Report
)
)
it works but if you change your structure maybe it won't. It's not optimized too :)
$input = Array(
'GetMLCBRes' => Array(Array(
'Ord' => Array(Array(
'OrdId' => Array('DP Order ID')
)),
'ReqInf' => Array(Array(
'ReqDat' => Array('Date of Request')
)),
'Res' => Array('PDF Report')
))
);
foreach($input as &$in){
$sub = $in[0];
foreach($sub as $key => &$value){
$sub2 = $value[0];
if(!is_array($sub2)){
$sub[$key] = $sub2;
continue;
}
$final2 = array();
foreach($sub2 as $key2 => $final)
$final2[$key2] = $final[0];
$sub[$key] = $final2;
}
$in = $sub;
}
var_dump($input);
You can test it here : http://sandbox.onlinephpfunctions.com/code/a6770c7649d7d277aa1dc3544093cc87bed0951d
This should work as expected :
function recursive_skip(array $ary) {
foreach($ary as $k => &$v) {
if (is_array($v)) {
// Skip it
$v = $v[0];
}
if (is_array($v)) {
// If current array item is an array itself, recursively call the function on it
$v = recursive_skip($v);
}
}
// Return updated array to calling context
return $ary;
}
$source = Array(
'GetMLCBRes' => Array(Array(
'Ord' => Array(Array(
'OrdId' => Array('DP Order ID')
)),
'ReqInf' => Array(Array(
'ReqDat' => Array('Date of Request')
)),
'Res' => Array('PDF Report')
))
);
$dest = recursive_skip($source);
var_dump($dest);
A few caveats : the function will only skip one array level each time (but could be adapted to handle more if needed) and might come with a significant performance cost if your source array is huge since it's recursive (O(n)), it just walks through the whole array tree.

Creating Associative Array in PHP

I have a multidimensional array.
$shop = array(
array("appn1", "pub1" ,"pub2" , "pub3"),
array("appn2", "pub1"),
array("appn3", "pub1" ,"pub2")
);
The first item in each array is application number and the rest in each array are the publication numbers. I get the first item(application number) and the last item of each array(latest publication number) like this
$index = count(array_keys($shop));
for($i=0;$i<$index;$i++){
$appln_nr = $shop[$i][0];
echo $appln_nr;
$publn_nr_index = count(array_keys($shop[$i]))-1;
$publn_nr = $shop[$i][$publn_nr_index];
echo $publn_nr;
}
Now I have application number and publication number for each inner array.
I want to create an associative array from the application numbers and publication numbers.
where the key should be the application number and its value is the publication number.
Thanks
EDIT
What I am getting from $shop array
Array
(
[0] => Array
(
[0] => appn1
[1] => pub1
[2] => pub2
[3] => pub3
)
[1] => Array
(
[0] => appn2
[1] => pub1
)
[2] => Array
(
[0] => appn3
[1] => pub1
[2] => pub2
)
)
And this is what I need in my associative array
Array(
"appn1" => "pub3"
"appn2" => "pub1"
"appn3" => "pub2"
)
Finally i understood what you wanted, after your edit XD:
$shop = array(
array("appn1", "pub1" ,"pub2" , "pub3"),
array("appn2", "pub1"),
array("appn3", "pub1" ,"pub2")
);
$shopNew = array();
foreach($shop as $value){
$shopNew[$value[0]] = end($value);
}
// now if you want you can replace $shop and unset $shopNew
$shop = $shopNew;
unset($shopNew);
print_r($shop);
the output is this:
Array (
[appn1] => pub3
[appn2] => pub1
[appn3] => pub2
)
You can try
$shop = array(
array("appn1","pub1","pub2","pub3"),
array("appn2","pub1"),
array("appn3","pub1","pub2")
);
$final = array();
array_map(function ($var) use(&$final) {$final[reset($var)] = end($var);}, $shop);
var_dump($final);
Output
array
'appn1' => string 'pub3' (length=4)
'appn2' => string 'pub1' (length=4)
'appn3' => string 'pub2' (length=4)
You can easily convert your array into a new format by using the first element as key (see reset) and the last element (see end) as value:
foreach($shop as $fl) {
$v[reset($fl)] = end($fl);
}
Result is in $v then.
If you want to transform the array you need to delete each element as well:
foreach($shop as $v => $fl) {
$shop[reset($fl)] = end($fl);
unset($shop[$v]);
}
Result is in $shop then. Unset takes care of removing from the array.
Output in both cases is:
array(3) {
'appn1' =>
string(4) "pub3"
'appn2' =>
string(4) "pub1"
'appn3' =>
string(4) "pub2"
}
try this:
foreach($shop as $k => $v) {
$new_arr[$v[0]] = end($v);
}
It should give you this result,
$new_arr = array(
"appn1" => "pub3",
"appn2" => "pub1",
"appn3" => "pub2"-
);
You can also create like this,
$arrField = [];
$arrField['id'] = '0001';
$arrField["first_name"] ='Demo Test';
print_r($arrField);
print_r($arrField) display output like this.
Array ( [id] => 0001 [first_name] => Demo Test )

Group 2d array data using column value to create a 3d array

I have a multidimensional array and am trying to group them according to the value in a specific column.
I'm trying to group them by level, but I won't actually know the level beforehand. So, it's not like I can put it in a for loop and say while $i < 7, because I won't know that 7 is the maximum value for the level key, and frankly, I'm not sure that's how I would need to do it even if I did.
[
['cust' => 'XT8900', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8944', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8922', 'type' => 'premier', 'level' => 3],
['cust' => 'XT8816', 'type' => 'permier', 'level' => 3],
['cust' => 'XT7434', 'type' => 'standard', 'level' => 7],
]
Desired result:
Array (
[1] => Array (
[0] => Array (
[cust] => XT8900
[type] => standard
)
[1] => Array (
[cust] => XT8944
[type] => standard
)
)
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
)
Best way, if you have control over building the initial array, is just set things up like that at the start as you add entries.
If not then build a temporary array to sort:
foreach ($input_arr as $key => &$entry) {
$level_arr[$entry['level']][$key] = $entry;
}
Leaves you with the form you wanted and everything referenced together.
Build the array like that in the first place though if at all possible.
You need to group them by level first
Use foreach to loop into array check if the level is the same with the previous item then group it with that array
$templevel=0;
$newkey=0;
$grouparr[$templevel]="";
foreach ($items as $key => $val) {
if ($templevel==$val['level']){
$grouparr[$templevel][$newkey]=$val;
} else {
$grouparr[$val['level']][$newkey]=$val;
}
$newkey++;
}
print($grouparr);
The output of print($grouparr); will display like the format you hoped for
You can also try to
print($grouparr[7]);
Will display
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
Or
print($grouparr[3]);
Will display
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
Here is the solution I landed on for an identical problem, wrapped as a function:
function arraySort($input,$sortkey){
foreach ($input as $key=>$val) $output[$val[$sortkey]][]=$val;
return $output;
}
To sort $myarray by the key named "level" just do this:
$myArray = arraySort($myArray,'level');
Or if you didn't want it as a function, just for a one time use, this would create $myNewArray from $myArray grouped by the key 'level'
foreach ($myArray as $key=>$val) $myNewArray[$val['level']][]=$val;
function group_assoc($array, $key) {
$return = array();
foreach($array as $v) {
$return[$v[$key]][] = $v;
}
return $return;
}
//Group the requests by their account_id
$account_requests = group_assoc($requests, 'account_id');
$result = array();
foreach ($yourArrayList as $data) {
$id = $data['level'];
if (isset($result[$id])) {
$result[$id][] = $data;
} else {
$result[$id] = array($data);
}
}
Best ans.
$levels = array_unique(array_column($records, 'level'));
$data = array();
foreach($records as $key => $value){
$data[$levels[array_search($value['level'],$levels )]][] = $value ;
}
print_r($data);
To generate the question's exact desured output from the sample input, pull/pop the last value from each row, use that value as the first level grouping key. Then use the original first level index as the second level key. Then push the two remaining elements into the group's subset.
Code: (Demo)
$result = [];
foreach ($array as $key => $row) {
$result[array_pop($row)][$key] = $row;
}
var_export($result);
For functional style syntax, use array_reduce(). (Demo)
var_export(
array_reduce(
array_keys($array),
function($result, $key) use ($array) {
$result[array_pop($array[$key])][$key] = $array[$key];
return $result;
}
)
);
function _group_by($array,$key,$keyName)
{
$return = array();
foreach($array as $val) {
$return[$keyName.$val[$key]][] = $val;
}
return $return;
} //end of function

Categories