array_column doesn't work with first key in nested array - php

I have a nested array like so
$array = array(
[2] => array(
[5] => array(
[7] => array(
[46] => array()
)
),
[108] => array()
),
[14] => array(),
[8] => array(
[72] => array()
)
)
With only knowing the key, I need to find it in the array and get all it's nested data. Using array_column only works if I start with a second level key
$foo = array_column($array, 2) // returns empty array
$bar = array_column($array, 5) // returns all its nested data
Why is that and what's the correct way to do this with any key without knowing the level

This is a recursive function which at each point checks if the key matches the required one, if so it returns the value, if not it will look in elements which are also arrays (which is where the recursive bit comes in) and return if a match is found there...
function nested_array_key_search ( array $array, $key ) {
foreach ( $array as $elementKey => $element ) {
if ( $elementKey === $key ) {
return $element;
}
if ( is_array($element) ) {
$nested = nested_array_column ( $element, $key );
// If the recursive call returns a value
if ( $nested !== false ) {
return $nested;
}
}
}
// Not found, return false
return false;
}
$bar = nested_array_key_search($array, 2);
print_r($bar);
gives...
Array
(
[5] => Array
(
[7] => Array
(
[46] => Array
(
)
)
)
[108] => Array
(
)
)

Related

Iterating through a one dimensional array and sorting it such that it becomes a two dimensional array based on key strings

For example, is there a logical way for me to iterate through this one dimensional array;
Array
(
[featured_video_video_type] => array()
[featured_video_video_mp4] => array()
[featured_video_video_webm] => array()
[featured_video_closed_captions] => array()
[featured_video] => array()
[content] => array()
[content_0_title] => array()
[content_0_content] => array()
[content_1_quote] => array()
[content_1_citation] => array()
)
And matching the keys such that I turn it into the following two dimensional array?
Array
(
[featured_video] => array(
[video] => array(
[type] => array()
[mp4] => array()
[webm] => array()
[closed_captions] => array()
)
)
[content] => array(
[0] => array(
[title] => array()
[content] => array()
)
[1] => array(
[title] => array()
[content] => array()
)
)
I should add that it needs to work without knowing what keys will appear in the array. I can do it if I know the keys by just mapping the beginning of the array keys but totally dumbfounded as to how to do it otherwise.
EDIT: Adjusted video 2D array
This looks like a really tough one. You could probably work through it with enough time, but I'm not sure how much time you have to devote to it. Here's how I would start:
<?php
function parse_the_array($array) {
$keys = array_keys( $array );
foreach( $keys as $i => $key ) {
$key_words = explode('_', $key);
$matches = 0;
$j = $i;
while(1) {
$next_key = $keys[++$j];
if ( ! empty( $next_key ) ) {
$next_key_words = explode('_', $next_key);
if ( $next_key_words[0] === $key_words[0] ) {
//The next key is a match, put it in an array of matching keys and increment matches
$matches++;
} else {
//The next key is not a match, break out
break;
}
} else {
break;
}
}
if ( $matches > 0 ) {
// Now you have to compare all the matches and see how many words
// they have in common to decide what the lowest level key is.
}
}
}
Like I said, it's a tough one. It would take a long time for me to get it right, and I'd have to know the constraints of what the keys could be. A simpler solution would be to break every underscore into a separate key so you have:
Array
(
[featured] => array(
[video] => array(
[video] => array(
[type] => array()
)
[video] => array(
[mp4] => array()
)
[video] => array(
[webm] => array()
)
[closed] => array(
[captions] => array()
)
)
)
...
)
Seemed like an interesting little problem, here is my attempt
I doubt it does everything you need, but should be enough to get you started
<?php
$rows = array(
'featured_video_video_type' => array(),
'featured_video_video_mp4' => array(),
'featured_video_video_webm' => array(),
'featured_video_closed_captions' => array(),
'featured_video' => array(),
'content' => array(),
'content_0_title' => array(),
'content_0_content' => array(),
'content_1_quote' => array(),
'content_1_citation' => array(),
);
$prefixes = ['featured_video', 'content'];
$output = [];
foreach ($rows as $key => $val) {
foreach ($prefixes as $prefix) {
if ($key === $prefix) {
// exact match, ignore
continue;
}
if (strpos($key, $prefix) !== 0) {
// doesn't match prefix, ignore
continue;
}
$new_key = substr($key, strlen($prefix)); // remove prefix
$new_key = ltrim($new_key, '_'); // remove any leading _
// match on pattern like 0_text
if (preg_match("/(\d+)_(.+)/", $new_key, $matches)) {
$idx = $matches[1];
$new_key = $matches[2];
$output[$prefix][$idx][$new_key] = $val;
}
else {
$output[$prefix][$new_key] = $val;
}
}
}
print_r($output);
Array
(
[featured_video] => Array
(
[video_type] => Array
(
)
[video_mp4] => Array
(
)
[video_webm] => Array
(
)
[closed_captions] => Array
(
)
)
[content] => Array
(
[0] => Array
(
[title] => Array
(
)
[content] => Array
(
)
)
[1] => Array
(
[quote] => Array
(
)
[citation] => Array
(
)
)
)
)

How to update an Associative Array

I do not know what is wrong with my php code. I want to have an Associative Array in the format. When I run my code I get this data. [KY] is an array in the [OH] array.
Array ( [Oh] => Array ( [state] => Oh ) [income] => 100 [count] => 1 [Ky] => Array ( [state] => Ky ) )
Array (
[OH] => Array
( [income] =>
[count] =>
)
[KY] => Array
( [income] =>
[count] =>
)
Here is my code
Example data in $array
Array ( [0] => Array (
[SurveyDate] => 1952-06-21
[Income] => 100
[CountyState] => Hamilton|Oh
[count] => 1 ) )
function update_array_value3( $array )
{
foreach ($array as $row)
{
$arrCountyState = explode( "|", $row['CountyState'] );
$key = $arrCountyState[1]; // OH or KY
if( !isset( $_SESSION['sIncome'][$key] ) )
{
$_SESSION['sIncome'][$key]['state'] = $key;
$_SESSION['sIncome'][$key]['income'] = $row['Income'];
$_SESSION['sIncome'][$key]['count'] = 1;
} else
{
$_SESSION['sIncome'][$key]['state'] = $key;
$_SESSION['sIncome'][$key]['income'] += $row['Income'];
$_SESSION['sIncome'][$key]['count'] += 1;
}
}
I can't tell you the root cause of the problem simply based on this snippet of code, but it seems $row either doesn't contain the data you expect it to, or doesn't contain any data.
In your code you reference $row['CountyState'], yet I don't see any array item called CountyState in $array.
Also, I'm not sure whether or not this is intentional, but in your foreach() loop it looks like $_SESSION['sIncome']['income'] and $_SESSION['sIncome']['count'] are being overwritten. Each time the loop encounters a new $key, it will overwrite those values.

PHP different 2 arrays and use conditions in comparison

I have 2 arrays follow this:
Array A
Array
(
[0] => Array
(
[TD_CODE] => 24203
[CRS_NAME] => Adobe Photoshop CS6+CC
)
[1] => Array
(
[TD_CODE] => 24202
[CRS_NAME] => Advance Microsoft excel 2010/2007
)
[2] => Array
(
[TD_CODE] => 24197
[CRS_NAME] => Beginning Auditor Tools and Techniques
)
);
And Array B
Array
(
[0] => Array
(
[crs_id] => 1
[crs_ia_id] => 2017-6495
[crs_oracle_id] => 24653
[crs_name] => Windows8
[crs_start_date] => 2017-08-07
[crs_end_date] => 2017-08-11
)
[1] => Array
(
[crs_id] => 2
[crs_ia_id] => 2017-5013
[crs_oracle_id] => 24202
[crs_name] => Advance Microsoft excel 2010/2007
[crs_start_date] => 2017-02-08
[crs_end_date] => 2017-02-09
)
)
I want to make array A different array B.
The condition is to use TD_CODE of the array A compared to crs_oracle_id of array b And and take it as array C.
So The results are as follows.
Array
(
[0] => Array
(
[TD_CODE] => 24203
[CRS_NAME] => Adobe Photoshop CS6+CC
)
[1] => Array
(
[TD_CODE] => 24197
[CRS_NAME] => Beginning Auditor Tools and Techniques
)
);
How should I do?
You can use array_filter() with anonymous function to compare TD_CODE and crs_oracle_id
$array_c = array_filter($array_a, function($e) use($array_b) {
foreach ($array_b as $v) {
if ($v['crs_oracle_id'] == $e['TD_CODE']) {
return false;
}
}
return true;
});
print_r($array_c);
Get ids from second array which needs to be rejected, then add only those records which doesn't exists in this id array,
$rejected_ids = array_column($b,'crs_oracle_id');
$c = [];
foreach($a as $v){
if(!in_array($v['TD_CODE'], $rejected_ids)){
$c[] = $v;
}
}
print_r($c);
array_column — Return the values from a single column in the input array
Here is working demo
EDIT
Here is more optimized code,
$c = array_filter($a, function($v,$k) use($rejected_ids){
return !in_array($v['TD_CODE'], $rejected_ids);
},ARRAY_FILTER_USE_BOTH);
Here is working demo.
array_filter — Filters elements of an array using a callback function
ARRAY_FILTER_USE_BOTH - pass both value and key as arguments to callback instead of the value
If your PHP Version is below 5.5 Then Please use this function
if (! function_exists('array_column')) {
function array_column(array $input, $columnKey, $indexKey = null) {
$array = array();
foreach ($input as $value) {
if ( !array_key_exists($columnKey, $value)) {
trigger_error("Key \"$columnKey\" does not exist in array");
return false;
}
if (is_null($indexKey)) {
$array[] = $value[$columnKey];
}
else {
if ( !array_key_exists($indexKey, $value)) {
trigger_error("Key \"$indexKey\" does not exist in array");
return false;
}
if ( ! is_scalar($value[$indexKey])) {
trigger_error("Key \"$indexKey\" does not contain scalar value");
return false;
}
$array[$value[$indexKey]] = $value[$columnKey];
}
}
return $array;
}
}
ARRAY - A
$array_a = Array
(
'0' => Array
(
'TD_CODE' => '24203',
'CRS_NAME' => 'Adobe Photoshop CS6+CC'
),
'1' => Array
(
'TD_CODE' => '24202',
'CRS_NAME' => 'Advance Microsoft excel 2010/2007'
),
'2' => Array
(
'TD_CODE' => '24197',
'CRS_NAME' => 'Beginning Auditor Tools and Techniques'
)
);
ARRAY - B
$array_b = Array
(
'0' => Array
(
'crs_id' => '1',
'crs_ia_id' => '2017-6495',
'crs_oracle_id' => '24653',
'crs_name' => 'Windows8',
'crs_start_date' => '2017-08-07',
'crs_end_date' => '2017-08-11'
),
'1' => Array
(
'crs_id' => '2',
'crs_ia_id' => '2017-5013',
'crs_oracle_id' => '24202',
'crs_name' => 'Advance Microsoft excel 2010/2007',
'crs_start_date' => '2017-02-08',
'crs_end_date' => '2017-02-09'
)
);
ARRAY - C
$array_c = array();
foreach ($array_a as $a){
if(!in_array($a['TD_CODE'], array_column($array_b, 'crs_oracle_id'))) {
$array_c[] = array('TD_CODE' => $a['TD_CODE'],'CRS_NAME'=>$a['CRS_NAME']);
}
}
print_r($array_c);

Group related elements in array

I have an array in the following format:
[8106] => Array (
[id1] => 210470
[id2] => 216298
)
[8107] => Array (
[id1] => 210470
[id2] => 187145
)
[8108] => Array (
[id1] => 187145
[id2] => 216298
)
[8109] => Array (
[id1] => 187145
[id2] => 210470
)
[8110] => Array (
[id1] => 266533
[id2] => 249612
)
[8111] => Array (
[id1] => 249612
[id2] => 266533
)
I need to get it into the following format:
[0] => Array (
[0] => 266533
[1] => 249612
)
[1] => Array (
[0] => 187145
[1] => 210470
[2] => 216298
)
Basically, I need to extract all the ids, keep the relationships, but group them all together. I have a function to do this, but it takes forever (I am up to 30+ minutes on the number of rows I have to run through). Keys and order are unimportant. The relationship is all that is important. I am looking for a faster method. The function(s) I am using are below:
function getMatchingIDs($filteredArray)
{
$result = array();
$resultCount = 0;
foreach ($filteredArray as $details) {
$imaId1 = inMultiArray($details['id1'], $result);
$imaId2 = inMultiArray($details['id2'], $result);
if ($imaId1 === false && $imaId2 === false) {
$result[$resultCount++] = array(
$details['id1'],
$details['id2'],
);
} elseif (is_numeric($imaId1) === true && $imaId2 === false) {
$result[$imaId1][] = $details['id2'];
} elseif ($imaId1 === false && is_numeric($imaId2) === true) {
$result[$imaId2][] = $details['id1'];
} elseif ($imaId2 != $imaId1) {
$result[$imaId1] = array_merge($result[$imaId1], $result[$imaId2]);
unset($result[$imaId2]);
}
}
return $result;
}
function inMultiArray($elem, $array)
{
if (is_array($array) === true) {
// if the variable $elem is in the variable $array return true
if (is_array($array) === true && in_array($elem, $array) === true) {
return true;
}
// if $elem isn't in $array, then check foreach element
foreach ($array as $key => $arrayElement) {
// if $arrayElement is an array call the inMultiArray function to this element
// if inMultiArray returns true, than return is in array, else check next element
if (is_array($arrayElement) === true) {
$value = inMultiArray($elem, $arrayElement);
if ($value === true) {
return $key;
}
}
}
}
// if isn't in array return false
return false;
}
$filtered = getMatchingIDs($unfiltered);
EDIT: The original array describes relations between pairs of ids (not shown in the array). The desired output is that the relations are further defined. If you look in the original array, elements 8106-8109 are simply paired combinations of three ids. I need those three grouped together. Elements 8110 and 8111 are a distinct pair, just in a different order.
$newArray = array();
foreach ($array as $k => $v) {
$newArray[0][] = $v['id1'];
$newArray[1][] = $v['id2'];
}
What I finally ended up doing was in essence creating an index array. This array held all the positions of each value in the primary array.
So the following array
[0] => Array (
[0] => 266533
[1] => 249612
)
[1] => Array (
[0] => 187145
[1] => 210470
[2] => 216298
)
has an index of:
[187145] => 1
[210470] => 1
[216298] => 1
[249612] => 0
[266533] => 0
So instead of looking for the value in the primary multidimensional array, I check to see if it exists in the index array and process the data based on that. The results are that it now runs the entire process in <5 seconds instead of > 1 hour.
Thank you for your help.

PHP - Compare two array and remove both item in a specific index if either of the array have empty value

Refer to 2 array below:
$bar_arr =
Array
(
Array
(
[bar] => bar01.jpg
[position] => 1
)
Array
(
[bar] => bar02.jpg
[position] => 2
)
Array
(
[bar] => bar03.jpg
[position] => 3
)
)
$banner_arr =
Array
(
Array
(
[banner] =>
[position] => 1
)
Array
(
[banner] => banner02.jpg
[position] => 2
)
Array
(
[banner] => banner03.jpg
[position] => 3
)
)
$banner_arr[0][banner] don't have value, so I would like to remove this index. In the meantime$bar_arr[0][bar] would also be removed, I want to end up like this:
$bar_arr =
Array
(
Array
(
[bar] => bar02.jpg
[position] => 2
)
Array
(
[bar] => bar03.jpg
[position] => 3
)
)
$banner_arr =
Array
(
Array
(
[banner] => banner02.jpg
[position] => 2
)
Array
(
[banner] => banner03.jpg
[position] => 3
)
)
My question is how to compare this two array and remove both item in a specific index if either of the array have empty value.
Thanks
If you're just checking the value of banner and you assume that the two arrays are ordered identically, this is fairly simple (You might need to make a copy of banner_arr first ... not sure):
foreach ($banner_arr as $key => $banner) {
if (empty($banner['banner'])) {
unset($banner_arr[$key]);
unset($bar_arr[$key]);
}
}
More likely though, the order of the arrays can't be relied upon. In this case, just use an additional array of positions and track all the positions that need to be removed, and unset those:
$positions = array();
foreach ($banner_arr as $key => $banner) {
if (empty($banner['banner'])) {
$positions[] = $banner['position'];
unset($banner_arr[$key]);
}
}
then search through $bar_arr for corresponding positions:
foreach ($bar_arr as $key => $bar) {
if (in_array($bar['position'], $positions)) {
unset($bar_arr[$key]);
}
}
I'm assuming that both arrays are the same length and that the only possible missing values are in ['bar'] or ['banner'].
Basically I'd just loop through the array and store the valid values in new arrays;
$new_bar_arr = array();
$new_banner_arr = array();
$count = count($banner_arr);
$index = 0;
while($index < $count){
if(!empty($bar_arr[$index]['bar']) && !empty($banner_arr[$index]['banner'])){
$new_bar_arr[] = $bar_arr[$index];
$new_banner_arr[] = $banner_arr[$index];
}
$index++;
}
Assuming your count lines up like you've suggested:
$newArray = array_map( NULL, $banner_arr, $bar_arr );
foreach( $newArray as $key => $array ){
foreach( $array as $arr ){
if( $arr === NULL ){
unset( $newArray[$key] );
}
}
}
Even if it doesn't, I'd just make a new function and use array map still.

Categories