PHP: Iterating Through a multidimensional Array (4D) - php

I have a multidimensional array structured like below. It mimics a file structure that is storing files based on ./YEAR/MONTH/DAY/FILE.
Array
(
[2019] => Array
(
[05] => Array
(
[12] => Array
(
[0] => default.md
)
)
[12] => Array
(
[22] => Array
(
[0] => default.md
)
)
)
[2020] => Array
(
[05] => Array
(
[19] => Array
(
[0] => default.md
)
)
)
)
I am trying to loop through the entire array and get the values for each specific file while also getting the associated YEAR, MONTH and DAY for that specified file.
My loop is way off as I am trying to nest multiple foreach loops inside of a for loop. The further down the rabbit hole I get, the more issues I encounter
$post_search = directoryArrayMap("content"); //function that creates the array
$year = array_keys($post_search);
for($i = 0; $i < count($post_search); $i++ ) {
echo $year[$i] . "<br>";
foreach($post_search[$year[$i]] as $month => $day ) {
echo $month[$i] . "<br>";
foreach($post_search[$key[$month[$i]]] as $day => $post_file ) {
echo $day . "<br>";
}
}
}
I am looking for the best way to iterate through a multidimensional array. Thanks. My desired output would be something like:
File A:
Year: 2020
Month: 05
Day: 12
File B:
Year: 2019
Month: 12
Day: 22
File C:
Year: 2019
Month: 05
Day: 19
The goal is to run this in conjunction with another loop that checks "is_file" and display the output.

By using a series of nested foreach with key => value iterators you can get the output you want; the key is not to output the date parts until you get to the bottom of the loops:
foreach ($post_search as $year => $months) {
foreach ($months as $month => $days) {
foreach ($days as $day => $files) {
foreach ($files as $file) {
echo "File $file:\nYear: $year\nMonth: $month\nDay: $day\n";
}
}
}
}
Output (for your sample data):
File default.md:
Year: 2019
Month: 5
Day: 12
File default.md:
Year: 2019
Month: 12
Day: 22
File default.md:
Year: 2020
Month: 5
Day: 19
Demo on 3v4l.org

Using functions to handle the confusing nested aspect should help a lot. By no means is my example a robust solution. And personally, I'd probably put the functions in a class & make it object oriented... but that's definitely not the right solution for every case.
You'll have to adapt this, but hopefully the concept is helpful.
function handleYear($year,$arrOfMonths){
echo $year;
foreach ($arrOfMonths as $month=>$arrOfDays){
handleMonth($month,$arrOfDays);
}
}
function handleMonth($month,$arrOfDays){
echo $month;
foreach ($arrOfDays as $dayOfMonth=>$listOfFiles){
handleDay($dayOfMonth,$listOfFiles);
}
}
//to get started
foreach ($data as $year=>$arrOfMonths){
echo $year;
handleYear($year, $arrOfMonths);
}
You could also modify the sub-functions to accept the parent paramaters. Like handleMonth could also take in the year, then handleYear just passes $year along.
EDIT:
After seeing your desired output... I'd suggest passing the year & month down to the handleDay function. Then handleDay could be something like:
function handleDay($day,$arrOfFiles,$year,$month) use (&$files){
foreach ($arrOfFiles as $index=>$fileName){
$file = ['year'=>$year,'month'=>$month,'day'=>$day];
$files[] = $file;
}
}
You would then need to declare $files = [] outside the function, before declaration of handleDay if I'm not mistaken.
But then you'd just have an array of files that you could work with pretty easily.
Personally, I'd probably toil away for awhile to come up with a cleaner solution (Not fond of the use statement in this case, which I might not even be using correctly). If it's in a class, then you could use $this->files instead of the use (&$files).

Related

PHP foreach from array

I am using an api to show a list of times but struggling to display them in using foreach
Here is how the data is shown:
stdClass Object
(
[id] => 2507525
[snapshotTimes] => Array
(
[0] => 2020-10-02T04:04:41+00:00
[1] => 2020-10-03T03:22:29+00:00
[2] => 2020-10-04T03:06:43+00:00
[3] => 2020-10-04T21:18:11+00:00
[4] => 2020-10-06T03:07:12+00:00
[5] => 2020-10-07T03:21:31+00:00
[6] => 2020-10-10T03:43:00+00:00
[7] => 2020-10-17T02:58:49+00:00
[8] => 2020-10-19T02:57:35+00:00
[9] => 2020-10-23T03:08:28+00:00
[10] => 2020-10-26T04:02:51+00:00
[11] => 2020-10-27T04:33:19+00:00
)
)
Code:
$domainArray = $services_api->getWithFields("/package/2507525/web/timelineBackup/web");
foreach ($domainArray as $arr) {
$Time = $arr->$domainArray->snapshotTimes;
echo " TIME: $Time<br>";
}
But it doesn't seem to echo anything at all? Where am I going wrong?
Your code shows;
$Time = $arr->$domainArray->snapshotTimes;
Here you're tying to access a property called domainArray on the array given by the foreach(). No need to do that since your already using the foreach() to loop over the data;
$domainArray = $services_api->getWithFields("/package/2507525/web/timelineBackup/web");
// For each item in the 'snapshotTimes' array
foreach ($domainArray->snapshotTimes ?? [] as $time) {
echo " TIME: {$time}<br>";
}
Try it online!
Note: Using the null coalescing operator (?? []) to ensure snapshotTimes exists in the data.
Based on comments; the same solution but with array_reverse() to reverse the output.
foreach (array_reverse($domainArray->snapshotTimes) as $time) {
....
Try it online!
You are triying to print snapshotTimes but you created a loop for another thing. If you want to print snapshotTimes code will be like :
foreach($arr->$domainArray->snapshotTimes as $time){
echo $time."</br>";
}
snapshotTimes is an array, but you are treating it as if it was a string. you should probably run another inner foreach to cycle through all values within snapshotTimes . Check your PHP Error log.
Perhaps an example would help him #Martin?
Example:
$domainArray = $services_api->getWithFields("/package/2507525/web/timelineBackup/web");
foreach ($domainArray as $arr) {
if(is_array($arr->snapshotTimes) && count($arr->snapshotTimes) > 0 ){
$times = $arr->snapshotTimes;
foreach($times as $timeRow){
echo " TIME: ".$timeRow."<br>";
}
unset($times); //tidy up temp vars.
}
}
I underline the point that you need to check your PHP Error Log to help you diagnose these sort of structure issues.
Notes:
Your reference $arr->$domainArray->snapshotTimes within the foreach is incorrect, you're referencing both the foreach label as well as the source of the foreach label, which will result in an error.
PHP variables should start with a lower case letter.
If you don't need $domainArray => $arr for any other reason within the foreach loop, you can simplify the loop by looping the array rather than the container, as 0stone0 shows on their answer.

How to loop with condition

This is my $update array
Array
(
[0] => 08:31:08
[1] => 08:32:08
[2] => 08:33:08
[3] => 10:34:08
[4] => 08:51:08
[5] => 08:21:08
[6] => 10:39:08
[7] => 08:41:08
[8] => 08:49:08
[9] => 08:20:08
[10] => 08:11:08
[11] => 10:50:08
)
This is my code
$default_computed = 9:30:00
$timin ="";
for ($x=0; $x < count($update) ; $x++) {
if (strtotime($update[$x]) > strtotime($default_computed) ) {
$timin .= $update[$x].',';
$replace_timin = substr_replace($timin ,"",-1);
$updated_timin = explode(",",$replace_timin);
$late_time_in = count($updated_timin);
echo "<pre>";
print_r($update);
print_r($timin);
die();
}
}
i want this output but its stop already for 1 time
10:34:08,10:39:08,10:50:08,
how can i loop continuously to get my target output?
I'm assuming your script is trying to figure out which time inside the array is beyond the cutoff time (which is $default_computed = 9:30:00).
With this in mind, I'd suggest you take on a different approach on this problem and avoid string manipulations (using substr_replace, explode and such) and start using DateTime classes instead:
$default_computed = '9:30:00'; // cutoff time
$cutoff = new DateTime($default_computed); // using DateTime
foreach ($update as $time) { // so each time element inside the array
$time_in = new DateTime($time); // load each time
if ($time_in >= $cutoff) { // if this time is beyond the cutoff
echo $time_in->format('H:i:s'); // output it
}
}
They're much easier and straightforward to use since you just load in the time and you can compare DateTime to DateTime objects directly in the if conditions.
So its basically each time in inside the array compared to the cutoff time.
$update = array
(
'08:31:08',
'08:32:08',
'08:33:08',
'10:34:08',
'08:51:08',
'08:21:08',
'10:39:08',
'08:41:08',
'08:49:08',
'10:50:08'
);
$default_computed = '9:30:00';
$default_computed= date("H:i:s", strtotime($default_computed)); // Convert your string to time
for($i=0; $i < count($update) ; $i++){
$update[$i]= date("H:i:s", strtotime($update[$i])); //Convert each elements of the array into time format
if($update[$i]>$default_computed)
echo $update[$i].",";
}

converting each element of array into time using date() in php

i have an array in php like the one given below
$each_session_time=array("2700","3356","3278","5452");
the issue is i want to convert each element in this array into time
i tried using
date("h:i:s",$each_session_array);
but it didn't work because date function doesn't work with arrays...
so can anyone help me in converting the each element into time....I shall be very thankful to you
$each_session_time=array();
for ($i=0; $i<sizeof($array_in_time_str) ; $i++) {
$each_session_time[$i]=$array_out_time_str[$i]-$array_in_time_str[$i];
}
If I understood your request, then this is what you need : using array_map here is a demo
<?php
$each_session_time=array(2700,33522,2222278,1111452);
$res = array_map(function($elem){
return date ("H:i:s",$elem);
},$each_session_time);
print_r($res);
?>
you can try this.
$each_session_time=array("2700","3356","3278","5452");
foreach ($each_session_time as $key => $value) {
$timeArray[] = date("h:i:s",$value);
}
echo "<pre>";print_r($timeArray);
Output:
Array
(
[0] => 06:15:00
[1] => 06:25:56
[2] => 06:24:38
[3] => 07:00:52
)

Split strings into an array of dates

I have an array of timestamps that I'm importing from different XML files. This is how they look like:
<field name="timestamp">2015-04-16T07:14:16Z</field>
So I have a bunch of them stored in an array named $timestamps like this:
2015-04-16T07:14:16Z
2015-04-24T14:34:50Z
2015-04-25T08:07:24Z
2015-04-30T07:48:12Z
2015-05-02T08:37:01Z
2015-05-09T10:41:45Z
2015-05-01T07:27:21Z
2015-05-07T09:41:36Z
2015-05-12T04:06:11Z
2015-05-12T05:52:52Z
2015-05-12T11:28:16Z
I am only interested in the date part, not the time. I have tried splitting the string using the split() function.
$dates = array();
for ($i=0; $i<count($timestamps); $i++){
$dates = split ("T", $timestamps[$i]);
echo $dates[$i] . "<br>";
}
From what I understand it is storing the first part (before the T) then the part after the T. How can it store only the first part of each string?
When I try this:
echo $dates[1];
it outputs the first date fine. I'm not quite sure about the rest.
Any suggestions on a better way to accomplish this?
Thanks!
You should use strtotime and date, as opposed to string splitting and/or regex. This will help if your date format ever changes.
$dates = array();
foreach ($timestamps as $timestamp) {
$d = strtotime($timestamp);
$dates[] = date('Y-m-d', $d);
}
foreach ($dates as $date) {
echo $date . '<br/>';
}
I think splitting is not better the best is get date using date function easily. Very easy code:-
<?php
$dates = array('2015-04-16T07:14:16Z','2015-04-24T14:34:50Z','2015-04-25T08:07:24Z','2015-04-30T07:48:12Z','2015-05-02T08:37:01Z'); // i hope your dates array is like this
foreach($dates as $date){
echo date('Y-m-d',strtotime($date)).'<br/>';
}
?>
Output:- http://prntscr.com/78b0x4
Note:-I didn't take your whole array. Because it's easy to see and understand what i am doing there in my code. thanks.
You can simply use preg_replace() to remove all the "time" bits in the array:
$array = Array('2015-04-16T07:14:16Z', '2015-04-24T14:34:50Z', '2015-04-25T08:07:24Z');
// Remove "T" and anything after it
$output = preg_replace('/T.*/', '', $array);
print_r($output);
Outputs:
Array
(
[0] => 2015-04-16
[1] => 2015-04-24
[2] => 2015-04-25
)
There's no reason to drag date and strotime into this, that's just extra overhead. You have an expected, regular format already.
And I would also give a warning about using date functions: you may run into trouble with the values changing after you put them through date and strtotime depending on your server's date/time(zone) settings! Since your strings do not specify the timezone offset, you won't even be able to properly convert.. you'll just have to roll with whatever your server is at or pick one yourself.
The safer way to ensure the actual value doesn't change is to just parse it as a string. Splitting at the "T" is fine. You're just having trouble with how to handle the variables. Here is an example:
// example data
$timestamps =<<<EOT
015-04-16T07:14:16Z
2015-04-24T14:34:50Z
2015-04-25T08:07:24Z
2015-04-30T07:48:12Z
2015-05-02T08:37:01Z
2015-05-09T10:41:45Z
2015-05-01T07:27:21Z
2015-05-07T09:41:36Z
2015-05-12T04:06:11Z
2015-05-12T05:52:52Z
2015-05-12T11:28:16Z
EOT;
$timestamps=explode("\n",$timestamps);
$dates = array();
for ($i=0; $i<count($timestamps); $i++){
$d = explode("T", $timestamps[$i]);
$dates[] = $d[0];
}
print_r($dates);
output:
Array
(
[0] => 015-04-16
[1] => 2015-04-24
[2] => 2015-04-25
[3] => 2015-04-30
[4] => 2015-05-02
[5] => 2015-05-09
[6] => 2015-05-01
[7] => 2015-05-07
[8] => 2015-05-12
[9] => 2015-05-12
[10] => 2015-05-12
)

Using date() with in_array() or array_key_exists()

Here is an array I have to work with:
array ( [0] => monday [1] => thursday [2] => saturday [3] => sunday )
I need to run an if/else statement to check if today's day is in that array.
This does not work
// Pretend today is thursdsy
$day = date('l');
$list = array ( [0] => monday [1] => thursday [2] => saturday [3] => sunday );
if ( array_key_exists($day, $list) ) {
echo "its there";
} else {
echo "not there";
}
Neither does the in_array() version. Not sure if there is a problem using the date() with either of these functions?
If I print_r the $day i get the correct value 'thusday'
Your list has the data in the values instead of the keys.. that is why array_key_exists is failing. Instead use in_array (also since your array week days represented in all lower case... you should do the same with with the supplied $day to get a match)
if (in_array(strtolower($day), $list){
// whoop there it is..
} else {
// not here.
}

Categories