Parsing array values into multidimensional array - php

I have some data I retrieve from a JSON feed that currently is being parsed into an array like this: (simplifying for demonstration purposes)
So pretty much an array returns a movie theater name, with the showtimes associated with that particular theater.
[0] => American Theater
[1] => 2014-06-04T13:10
[2] => 2014-06-04T15:10
[3] => Grand Theater
[4] => 2014-06-04T15:30
[5] => 2014-06-04T19:10
How would I parse this array to be multidimensional, for instance:
Array
(
[0] => Array
(
[theater] => Array
(
[name] => American Theater
)
[showtimes] => Array
(
[1] => 2014-06-04T13:10
[2] => 2014-06-04T15:10
)
)
[1] => Array
(
[theater] => Array
(
[name] => Grand Theater
)
[showtimes] => Array
(
[1] => 2014-06-04T15:30
[2] => 2014-06-04T19:10
)
)
)

I'm assuming you're trying to access some api and have no control over how the data is passed back to you? If you do then the API should be responsible for returning a sensible schema.
But if you're forced to work with this array and the amount of showtimes are unknown to you, then you can do something like this:
$array = array(
'American Theater',
'2014-06-04T13:10',
'2014-06-04T15:10',
'Grand Theater',
'2014-06-04T15:30',
'2014-06-04T19:10'
);
$i = 0;
foreach ($array as $key => $value) {
if (strtotime($value)) {
$theaters[$i - 1]['showtimes'][] = $value;
}
else {
$theaters[$i]['theater']['name'] = $value;
$i++;
}
}
Outcome
To walk you through it, $array is whatever the returned dataset is. We set an index in the $i value and want to only increment it if we determine we've detected a theater name. Within the loop we first try to determine if the string can be converted to a php time value. If it cannot we add the theater name to our new schema structure, and increment our index value. Since times are always added to theater names, we are expecting the first index number to always be one higher than what we want to add the showtime to.
This will fail to be accurate in cases when a theater name is convertible to a time value in such cases like Next Month. There are a couple of other ways to solve this with regex or by inspecting the string for certain characters and their position since the time format will remain the same.
You could replace the strtotime() with:
$str = str_split($value);
if (($str[4] && $str[7]) == '-' && $str[10] == 'T' && $str[13] == ':' ) {
$theaters[$i - 1]['showtimes'][] = $value;
}

If you want such structure, you need to create a new copy of it. You may also need to chunk/group them by three's using array_chunk first, and then, from there, you can loop it now and start creating the desired format.
Consider this example:
$old_values = array('American Theater', '2014-06-04T13:10', '2014-06-04T15:10', 'Grand Theater', '2014-06-04T15:30', '2014-06-04T19:10');
$old_values = array_chunk($old_values, 3);
$new_values = array();
foreach($old_values as $key => $value) {
$new_values[] = array(
'theater' => array('name' => $value[0]),
'showtimes' => array(1 => $value[1], 2 => $value[2]),
);
}
Edit: As mentioned, one theater can have many showtimes, therefore this current solution will fail. This may be an alternative (you may need to check each element if its a theater name or a date). Consider this example:
$old_values = array(
'American Theater',
'2014-06-04T13:10',
'2014-06-04T15:10',
'Grand Theater',
'2014-06-04T15:30',
'2014-06-04T19:10',
'Magic Johnson Theater',
'2014-06-04T19:10',
'2014-06-04T19:10',
'2014-06-04T19:10',
'Mall of America Theater',
'2014-06-04T19:10',
'2014-06-04T19:10',
'2014-06-04T19:10',
'2014-06-04T19:10',
);
$new_values = array();
$current_key = 0;
foreach($old_values as $key => $value) {
$current_value = $value;
$pieces = explode('T', $current_value);
$dates = explode('-', $pieces[0]);
if(count($dates) == 3) {
$new_values[$current_key]['showtimes'][] = $current_value;
} else {
$current_key++;
$new_values[$current_key]['theater']['name'] = $current_value;
}
}
Sample Output:
Array
(
[1] => Array
(
[theater] => Array
(
[name] => American Theater
)
[showtimes] => Array
(
[0] => 2014-06-04T13:10
[1] => 2014-06-04T15:10
)
)
[2] => Array
(
[theater] => Array
(
[name] => Grand Theater
)
[showtimes] => Array
(
[0] => 2014-06-04T15:30
[1] => 2014-06-04T19:10
)
)
[3] => Array
(
[theater] => Array
(
[name] => Magic Johnson Theater
)
[showtimes] => Array
(
[0] => 2014-06-04T19:10
[1] => 2014-06-04T19:10
[2] => 2014-06-04T19:10
)
)
[4] => Array
(
[theater] => Array
(
[name] => Mall of America Theater
)
[showtimes] => Array
(
[0] => 2014-06-04T19:10
[1] => 2014-06-04T19:10
[2] => 2014-06-04T19:10
[3] => 2014-06-04T19:10
)
)
)
Sample Fiddle

Related

Taking out just one value from an array

I have an array which is
Array ( [0] => Array ( [picture] => 5a55ed8d8a5c8910913.jpeg
[id] => 1284
[price_range] => Rs 12000 - 9000
[name] => Brown Beauty Office Chair )
[1] => Array ( [picture] => 5a55eefeb9a8e255836.jpeg
[id] => 1285
[price_range] => Rs 8989 - 7000
[name] => Chang Series Office Chair (Grey)
)
)
Now I am fetching the value of id on clicking a remove button, the value I fetch is 1284.
I want to take out just [id]=> 1284 from the above array and then display it using a foreach loop. How I can delete just the [id]=> 1284 without disturbing the other id values and other element.
In the above array I would like to delete one particular id value say just the [id]=> 1284 and keep all other elements intact and as it is.
Any help is welcome.
Use array_search and array_column, to find by id and remove by unset method,
<?php
$array = [
["id"=>123,"desc"=>"test1"],
["id"=>456,"desc"=>"test2"],
["id"=>789,"desc"=>"test3"],
];
$id = 456;
$index = array_search($id, array_column($array, 'id'));
unset($array[$index]);
print_r($array);
?>
Live Demo
Array
(
[0] => Array
(
[id] => 123
[desc] => test1
)
[2] => Array
(
[id] => 789
[desc] => test3
)
)
Since you asked how to achieve it using foreach, I came up with this.
$array = Array (Array ( 'picture' => '5a55ed8d8a5c8910913.jpeg','id' => 1284,'price_range' => 'Rs 12000 - 9000', 'name' => 'Brown Beauty Office Chair'),
Array ( 'picture' => '5a55eefeb9a8e255836.jpeg','id' => 1285,'price_range' => 'Rs 8989 - 7000','name' => 'Chang Series Office Chair (Grey)')
);
foreach($array as $key => $val) {
$id = $array[$key]['id'];
if($id === 1284){
unset($array[$key]['id']);
}
}
print_r($array)
?>
You can also use this too:
<?php
$element_to_remove = 1284;
$i = 0;
foreach($array as $this_arr){
$index = array_search($element_to_remove, $this_arr);
//unset($this_arr[$index]); this formate does not remove element from array
//but below works fine
if(isset($array[$i][$index])){
unset($array[$i][$index]);
}
}
print_r($array);
?>

Creating and pushing to arrays

I am trying to create an array(if it does not already exist) and then push values to it.
foreach($playlist->items as $item) {
$str = $item->snippet->title;
$id = $item->snippet->resourceId->videoId;
$substring = substr($str, 0, 5);
$substring = strtolower($substring);
if (is_array($substring)) {
array_push($substring, $id);
}
else {
$substring = array();
array_push($substring, $id);
}
array_push($artists, $substring);
}
I am iterating through data retrieved from a Youtube playlist, so I go through each item with foreach which holds a 'title' - the artist and an 'id' - the video Id . I substring each title and try to use this to group artists into specific arrays.
If an array already exists for that artist, I try to push the 'id' onto the end of that array. If an array does not exist, I create one and then push the 'id' onto that array.
At the end I try to push each artist array into the 'artists' array.
What I get when I print out $artists array is something like this
Array
(
[0] => Array
(
[0] => 1_YUrdjLyAU
)
[1] => Array
(
[0] => Gp8lDW2LUM0
)
...
[543] => Array
(
[0] => Exa0CzlCb3Y
)
Every single $id is in it's own array when they should be grouped together based on $substring. e.g
Array
(
[0] => Array
(
[0] => 1_YUrdjLyAU
[1] => 1_YUrdjLyAU
[2] => 1_YUrdjLyAU
[3] => 1_YUrdjLyAU
[4] => 1_YUrdjLyAU
)
[1] => Array
(
[0] => Gp8lDW2LUM0
[1] => 1_YUrdjLyAU
[2] => 1_YUrdjLyAU
[3] => 1_YUrdjLyAU
)
What am I not understanding?
Here is a simpler solution to your problem:
$artists = array();
foreach($playlist->items as $item) {
$artist = $item->snippet->artist; // however the artist name is fetched..
$id = $item->snippet->resourceId->videoId;
$artists[$artist][] = $id
}
This way, you don't need to check if an artist is already in the array, it will do that automatically and append the video id to the artist.
The $artists array will be assosiative, I don't think you can do it with a numeric array.
The array will look like this:
Array
(
['Jon Lajoie'] => Array
(
[0] => 1_YUrdjLyAU
[1] => lf3hflkap39
[2] => 1vt1455zzbe
[3] => 6dthg3drgjb
[4] => jfop3ifjf3p
)
['Lonely Island'] => Array
(
[0] => Gp8lDW2LUM0
[1] => 5he5hj67j7r
[2] => krt7tkktzk8
[3] => we54w4ggsrg
)
)
Use substring as array key and do following:
**Remove**
if (is_array($substring)) {
array_push($substring, $id);
}
else {
$substring = array();
array_push($substring, $id);
}
array_push($artists, $substring);
**Replace**
$artist[$substring][]=$id;

PHP loop to get the data I need

I am using an API and am using a few foreach loops to get to the stage that I am at right now. Please see code below with my comments and also the results that I am getting below that.
// get recent_games api data
$recent_games_data = $player->recent_games();
//start arrays for below
$matches = array();
$gameType = array();
$myData = array();
// using foreach loops to dig in to api data
foreach($recent_games_data['gameStatistics']['array'] as $key_match_data => $value_match_data) {
$matches[] = $value_match_data['statistics'];
}
foreach($matches as $key_match) {
$gameType[] = $key_match['array'];
}
foreach ($gameType as $keyz) {
$myData[] = $keyz;
}
The $mydata array outputs this data below.
Array
(
[0] => Array
(
[0] => Array
(
[statType] => TRUE_DAMAGE_DEALT_TO_CHARACTER
[dataVersion] => 0
[value] => 3351
[futureData] =>
)
[1] => Array
(
[statType] => ASSISTS
[dataVersion] => 0
[value] => 14
[futureData] =>
)
[2] => Array
(
[statType] => NUM_DEATHS
[dataVersion] => 0
[value] => 3
[futureData] =>
)
)
[1] => Array
(
[0] => Array
(
[statType] => TRUE_DAMAGE_DEALT_TO_CHARACTER
[dataVersion] => 0
[value] => 331
[futureData] =>
)
[1] => Array
(
[statType] => ASSISTS
[dataVersion] => 0
[value] => 4
[futureData] =>
)
[2] => Array
(
[statType] => NUM_DEATHS
[dataVersion] => 0
[value] => 7
[futureData] =>
)
)
Of course there is much more data but this is basically what I have now. The first array [0] is each match and the second array are the statistics for that match. What I want is how do I get the statistics of each match without hardcoding the match array number, for example below.
$myData[0][0]['statType']
Let me know if you need more info and thank you.
EDIT: sorry for to mention that as new statistics data gets added to the api, the index number changes. IE TRUE_DAMAGE_DEALT_TO_CHARACTER is [0] to begin with but then may change to [1] or [2] etc.
Consider implementing a class for your stats items after parsing through the data (independent of individual match information keys):
class Stat_Item {
function __construct($id, $info) {
$this->id = $id;
if(!empty($info['damage'])
$this->damage_dealt = $info['damage'];
if(!empty($info['assists']))
$this->assists = $info['assists'];
if(!empty($info['deaths']))
$this->deaths = $info['deaths'];
}
}
$parsed_items = array();
foreach($mydata as $match_id => $match) {
$info = array();
foreach($match as $data_point) {
switch($data_point['statType']) {
case TRUE_DAMAGE_DEALT_TO_CHARACTER:
$info['damage'] = $data_point['value'];
break;
case ASSISTS:
$info['assists'] = $data_point['value'];
break;
case NUM_DEATHS:
$info['deaths'] = $data_point['value'];
break;
}
$parsed_items[] = new Stat_Item($match, $info);
}
}
Other than looping through them all, I don't see any way for you to get a particular match without calling it by its index.
You don't need several foreach loops - you can add to all three arrays in a single one. Also, it looks like $gameType and $myData end up containing the same data.
foreach($recent_games_data['gameStatistics']['array'] as $key_match_data => $value_match_data) {
$matches[] = $value_match_data['statistics'];
$gameType[] = $value_match_data['statistics']['array'];
$myData[] = $value_match_data['statistics']['array'];
}
I don't really understand why you don't just put it into the same array so you can access it easily, though:
foreach($recent_games_data['gameStatistics']['array'] as $key_match_data => $value_match_data) {
$matches[] = array('statistics' => $value_match_data['statistics'], 'data' => $value_match_data['statistics']['array']);
}

Combination of arrays

I have tried to get the below code to work for a good couple of hours, but just don't succeed.
I have this date array:
Array ( [0] => Array ( [0] => 2007 )
[1] => Array ( [0] => 2008 )
[2] => Array ( [0] => 2009 )
...
)
and this plusMinus one:
Array ( [0] => Array ( [plus] => 2 [date] => 2007 )
[1] => Array ( [minus] => 1 [date] => 2008 )
[2] => Array ( [minus] => 1 [date] => )
[3] => Array ( [plus] => 1 [date] => 2010 [minus] => 1 )
)
I have been trying to combine them into this:
Array ( [0] => Array ( [date] => 2007 [plus]=> 2)
[1] => Array ( [date] => 2008 [minus]=> 1)
[2] => Array ( [date] => 2009 [plusMinus]=> 0)
[3] => Array ( [date] => 2010 [plus] => 1 [minus]=>1 )
...
)
So basically I want to check if a value of the date array exists in the plusMinus array. If true the date and values from the plusMinus array shall replace the entry in the date array.
If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
The way I have tried to do it is this:
foreach ($filler as $key1 => $value1)
{
foreach ($plusMinus as $key2 => $value2)
{
if ($value1['0'] !== $value2['date'])
{
$value1['plusMinus'] = '0';
$result2[$key1][] = $value1;
}
elseif ($value1['0'] == $value2['date'])
{
if (array_key_exists('plus',$value2))
{
$value1['plus'] = $value2['plus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2))
{
$value1['minus'] = $value2['minus'];
$result2[$key1][]=$value1;
}
elseif(array_key_exists('minus',$value2) &&
array_key_exists('plus',$value2))
{
}
}
}
}
$valuesComplete = array();
foreach ($result2 as $value) {
$result2 = $value['0'];
array_push($valuesIncomplete, $result2);
}
return $valuesComplete;
Instead of the desired outcome described above I get this:
Array ( [0] => Array
( [0] => 2007 [plus] => 2 )
[1] => Array ( [0] => 2008 [plusMinus => 0 )
[2] => Array ( [0] => 2009 [plusMinus] => 0 )
[3] => Array ( [0] => 2010 [plusMinus] => 0 )
[4] => Array ( [0] => 2011 [plusMinus] => 0 )
[5] => Array ( [0] => 2012 [plusMinus] => 0 )
[6] => Array ( [0] => 2013 [plusMinus] => 0 )
)
What am I missing? Thanks for any help!
Unfortunately, because of the input data format, I can't see any way to do this that doesn't involve an O(n + m + p) operation. But no matter, you gotta do what you gotta do.
Firstly I would start by filtering the useless elements from the PlusMinus array. Since it's already fairly close to the desired output format, it makes sense to use this as the base of the result.
$temp = array();
foreach ($plusMinus as $item) {
if (!empty($item['date'])) {
$temp[$item['date']] = $item;
}
}
Notice that I used the date as the index of the temporary array we're using to build the result. This is to allow you to easily ensure that the result array is in the correct order, and to quickly check whether an item needs to be added from the Filler array.
Next, we need to add any missing elements from the Filler array:
foreach ($filler as $item) {
if (!isset($temp[$item[0]])) {
$temp[$item[0]] = array(
'date' => $item[0],
'plusMinus' => 0
);
}
}
Now all the data is in the array in the correct format, we just need to sort it:
ksort($temp);
...and get convert it back to an indexed array:
return array_values($temp);
No need for the performance killing nested loops or complex flow control.
See it working
As I understood you need to add years that not in second array but in first?
In that case you can do:
foreach ($filler as $key1 => $value1)
{
$ok = false;
foreach ($plusMinus as $key2 => $value2)
{
if($value2['date']==$value1[0])
{
$ok = true;
break;
}
}
if(!$ok)
{
$plusMinus[$value1[0]]=array('date'=>$value1[0], 'plusMinus'=>0);
}
}
<?php
$a1 = array(array( 2007 ),
array( 2008 )
);
$a2 = array(array('plus'=>1, 'date'=>2007),
array('minus'=>1,'date'=>2008),
array('plus'=>1, 'minus'=>1, 'date'=>2008)
);
$r = array();
foreach($a1 as $k1=>$d1) {
$year = $d1[0];
foreach( $a2 as $k2=>$d2 ) {
if( $d2['date'] == $year ) {
$r[$year]['date'] = $year;
if(isset($d2['plus'])) {
$r[$year]['plus'] = $d2['plus'];
}
if(isset($d2['minus'])) {
$r[$year]['minus'] = $d2['minus'];
}
}
}
}
print_r($r);
and result
Array
(
[2007] => Array
(
[date] => 2007
[plus] => 1
)
[2008] => Array
(
[date] => 2008
[minus] => 1
[plus] => 1
)
)
$ar1 = array( array(2007), array(2008), array(2009), array(2010) );
$ar2 = array(
array("date"=>2007, "plus"=>2),
array("date"=>2008, "minus"=>1),
array("date"=>"", "minus"=>1),
array("date"=>2010, "plus"=>1, "minus"=>1)
);
foreach($ar2 as $key=>$val){
if(isset($ar1[$key][0]))
$val["date"] = $ar1[$key][0];
$ar2[$key] = $val;
}
I am not sure if I understand you correctly but this works fine...
It will work only if you are sure that your both arrays "date" equals one to other..
This is what I came up with:
To not create the product of both arrays (foreach inside foreach), I first index the $plusMinus array with the date. That will allow to test quickly if a year exists or not:
$years = array_combine(array_column($plusMinus, 'date'), $plusMinus);
This uses the array_column() function of PHP 5.5, if you don't have it you can easily create it your own.
After doing that it is exactly how you wrote it in your own words:
foreach($date as &$entry)
{
list($year) = $entry;
$entry = array('date' => $year);
// check if a value of the date array exists in the plusMinus array.
if (isset($years[$year])) {
// If true the date and values from the plusMinus array shall replace the entry in the date array
$entry += $years[$year];
} else {
// If false, the original date array entry is complemented by a [plusMinus] => 0 key-value pair.
$entry += array('plusMinus' => 0);
}
}
unset($entry);
See it i action.
This will work just fine.
I did not at all understand your question, but if i got it this is the way:
First make your $datearray more understandable like this:
$dateArray = array(2007,2008,2009,2010);
$plusMinus = array(
array( 'plus' => 2 ,'date' => 2007),
array( 'minus' => 1 ,'date' => 2008),
array ( 'minus' => 1 , 'date' => '' ),
array ( 'plus' => 1 , 'date' => 2010 , 'minus' => 1 )
);
You can make it multidimensional later;
After that:
foreach($dateArray as $k=>$v)
{
if(in_array($v,$plusMinus[$k]))
{
$filler[$k] = $plusMinus[$k];
}
else{
if(empty($plusMinus[$k]['date']))
{
$filler[$k]['date']= $v;
$filler[$k]['plusMinus'] = 0;
}
}
}
This is simple and clean, understandable way with very little code if your arrays will always have the structure you described, meaning the plusMinus values for 2007 are in the cell [0] and the 2007 in the dateArrays is also in the cell [0] like you have shown. I hope i could help.

PHP splitting arrays into groups based on one field's value

I have an array containing arrays of names and other details, in alphabetical order. Each array includes the first letter associated with the name.
Array
(
[0] => Array
(
[0] => a
[1] => Alanis Morissette
)
[1] => Array
(
[0] => a
[1] => Alesha Dixon
)
[2] => Array
(
[0] => a
[1] => Alexandra Burke
)
[3] => Array
(
[0] => b
[1] => Britney Spears
)
[4] => Array
(
[0] => b
[1] => Bryan Adams
)
)
I'd like to display them grouped by that first initial, eg:
A
-
Alanis Morissette
Alesha Dixon
Alexandra Burke
B
-
Britney Spears
Bryan Adams
etc...
Is this at all possible?
You can group them easily, even if they aren't sorted:
$groups=array();
foreach ($names as $name) {
$groups[$name[0]][] = $name[1];
}
You don't even need to store the first initial to group them:
$names = array(
'Alanis Morissette',
'Alesha Dixon',
'Alexandra Burke',
'Britney Spears',
'Bryan Adams',
...
);
$groups=array();
foreach ($names as $name) {
$groups[$name[0]][] = $name;
}
Since your array is already sorted, you could just loop through and track the last letter shown. When it changes, you know you're on the next letter.
$lastChar = '';
foreach($singers as $s) {
if ($s[0] != $lastChar) echo "\n".$s[0]."\n - \n";
echo $s[1]."\n";
$lastChar = $s[0];
}

Categories