PHP Array Total Subchildren

I've got an array that's formatted like this...

[Group1] => Array
                (
                    [Group 2] => Array
                        (
                            [67] => Array
                                (
                                    [0] => 2015-09-25
                                    [1] => 2015-09-26
                                    [2] => 2015-09-27
                                    [3] => 2015-09-28
                                    [4] => 2015-09-29
                                    [5] => 2015-09-30
                                )

                            [68] => Array
                                (
                                    [0] => 2015-10-01
                                    [1] => 2015-10-02
                                    [2] => 2015-10-03
                                    [3] => 2015-10-04
                                    [4] => 2015-10-05
                                )

                        )

I'd like to test if the total number of secondary subchildren of Group 2 (the ones with dates) equals a variable...like in this case...11.  

What would the syntax of that be?

Thanks in advance!
LVL 2
erzoolanderAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Ray PaseurCommented:
I'm not sure that I understand your exact data structure, bit given what we have to work with, this will show the general design for how nested arrays can be counted.
http://iconoun.com/demo/temp_erzoolander.php

<?php // demo/temp_erzoolander.php

/**
 * See http://www.experts-exchange.com/Programming/Languages/Scripting/PHP/Q_28640105.html
 */
error_reporting(E_ALL);
echo '<pre>';

$dataset = array
( 'Group1' => Array
  ( 'Group 2' => Array
    ( '67' => Array
      ( '0' => 2015-09-25
      , '1' => 2015-09-26
      , '2' => 2015-09-27
      , '3' => 2015-09-28
      , '4' => 2015-09-29
      , '5' => 2015-09-30
      )
    , '68' => Array
      ( '0' => 2015-10-01
      , '1' => 2015-10-02
      , '2' => 2015-10-03
      , '3' => 2015-10-04
      , '4' => 2015-10-05
      )
    )
  )
)
;
var_dump($dataset);

$interesting = $dataset['Group1']['Group 2'][67];
$number = count($interesting);
echo PHP_EOL . "THERE ARE $number ELEMENTS IN THE INTERESTING PART OF THE ARRAY";

Open in new window

0
erzoolanderAuthor Commented:
Here's a better explanation of what I'm doing..  :)

I had another post I made a few days ago that you answered about grouping items together from a query.  It was in reference to a hotel agency reservations engine that I'm writing.  I wanted to make sure that all rates got lumped together under the relevant room - and that all rooms got grouped together under the right hotel.  The conclusion you and I came to was that multiple SQL queries might be in order.

I decided to go another direction - and instead dump the SQL results into an array using array keys as the grouping means.  That way I could just have one SQL query that would iterate through all of the rates - and it would push the rate into the relevant keys.  

So - instead of "Group 1", "Group 2" which might be confusing - more specifically it's...

[Hotel] => Array
                (
                    [Hotel Room] => Array
                        (
                            [Applicable Rate 1] => Array
                                (
                                    [0] => 2015-09-25
                                    [1] => 2015-09-26
                                    [2] => 2015-09-27
                                    [3] => 2015-09-28
                                    [4] => 2015-09-29
                                    [5] => 2015-09-30
                                )

                            [Applicable Rate 2] => Array
                                (
                                    [0] => 2015-10-01
                                    [1] => 2015-10-02
                                    [2] => 2015-10-03
                                    [3] => 2015-10-04
                                    [4] => 2015-10-05
                                )

                        )

Basically - my function:

1: Takes a date range.
2: Iterates through each day of the date range and checks to see if there's a relevant rate for that date.
3: If there's a relevant rate for that date - it grabs the room type, and the hotel, and appends it to the array grouped by the appropriate keys (rates grouped by room grouped by hotel).

It needs to be that way because it's possible that the date range might cross from one rate date range to another.  In the case I gave - there are two different dates - because the date of rate 1 terminates on one day - and then rate 2 commences the next.

Make sense?

That all works beautifully.  However - what I need to do is see if the summation of all rates equals the total dates I'm searching.  Like - if I were to search for 50 days - there could be 25 rates.  I need to know if those 25 rates (rate 1, rate 2...rate 25) together sum up to 50 (the number of dates queried).  

If the sum of rates resulting in the array equals the length of the date range I'm querying - then the hotel has an available spot to be reserved.  If it's fewer - that means that rates are not available for each date.

Does that explain what I'm looking for better?  I need to count the number of items iterated through rate 1, rate 2...rate x.  :)
0
erzoolanderAuthor Commented:
I'm thinking it will end up being some sort of...

forreach($array[rate] as $item) {
$x = count(key($item))+$x;
}

type of solution.  I just don't work with arrays a lot - and want help with the syntax.  

Or if I'm missing something and that wouldn't be the best approach - maybe there's something else?
0
Cloud Class® Course: SQL Server Core 2016

This course will introduce you to SQL Server Core 2016, as well as teach you about SSMS, data tools, installation, server configuration, using Management Studio, and writing and executing queries.

Brian TaoSenior Business Solutions ConsultantCommented:
This should do the work:
<?php
$level1 = array( // group1 or hotel
  "level2" => array( // group 2 or hotel room
    "level3_0" => array( // 67 or applicable rate 1
      "2015-09-25",
      "2015-09-26",
      "2015-09-27",
      "2015-09-28",
      "2015-09-29",
      "2015-09-30"
    ),
    "level3_1" => array( // 68 or applicable rate 2
      "2015-10-01",
      "2015-10-02",
      "2015-10-03",
      "2015-10-04",
      "2015-10-05"
    )
  )
);
var_dump($level1);

$x = 0;
foreach ($level1 as $level2){
  foreach($level2 as $level3){
    $x += count($level3);
  }
}
echo "<br>" . PHP_EOL;
echo "Grand total = $x";
?>

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Slick812Commented:
greetings erzoolander, , ,, you can use the  php  count( ) to get the number of elements in an array, as you know. And you can do foreach( ) loops through all of your date-rates array, BUT It may take more coding, because you say -
   "If there's a relevant rate for that date - it grabs the room type, and the hotel"
so you can have 2 or more hotels, and each hotel can have 2 or more room types, with 2 or more "Applicable Rates" per room.

And then you say - "If it's fewer - that means that rates are not available for each date.",  . ..
So I guess you need to delete that rate array from the array entries?
I am not sure , , what if any "action" in code is required for a "Applicable Rate" array that does not have the correct number of dates in that array. If you need to remove  "Applicable Rate" arrays from the "room type" arrays, your code may get more complex. You may can just keep an array record of the
 "hotel"-"room type"-"Applicable Rate"
elements that are NOT with the correct count, and block their display later?
I am just  guessing here, so if I am not seeing your steps toward the result you need then, just ignore me.
0
Ray PaseurCommented:
This really screams out for a little bit of object-oriented design.  If you can show us your data sources, we may be able to show you how to organize the data collection so that questions like this can be answered easily.  I'm speculating a little bit here, but there are some immutable parts of the data model and some that can change.  Here are the ones I see as essentially immutable:

The hotel
The rooms
The days on the calendar

Here are the ones I see as readily changeable, due to market influences:

The rate plans

What is the important relationship here?  It would be the association of rate plans with a room in a hotel on a date.

That leads me to a design that would have rate plans in a collection.  Each rate plan would have pointers to the days, the rooms, and the hotels.  To establish a rate plan for a hotel room on a given date you would just create a row in the junction table that contained pointers to all the applicable elements.

Make sense?
0
erzoolanderAuthor Commented:
Yep - makes sense.  In the database - that's pretty much how it's set up.

There are a number of different tables that pertain to the hotels themselves.  There are tables that pertain to the rooms - associated by an entity ID to the hotels.  Then there are tables that pertain to the rates - associated by an entity ID to the rooms.

The reason for my question about the arrays isn't so much for how the database is structured - but rather how I'm managing display once the query has been made.  I wanted a simple way of parsing the resulting data that came from... (simple example - not the exact query)

select * from rates t1
left join rooms t2 on t2.id = t1.id
left join hotels t3 on t3.rid = t2.rid
WHERE date1 > t1.date2 AND date1 < t1.date3

etc etc.

What I did after that is took all of the results and chucked it into an array - where rates were grouped by room ids, and room ids were grouped by hotel ids.  That way - in building out the page I could easily iterate through the array for display.  The keys served as the hierarchy (one hotel, multiple rooms, etc) without having to do secondary sql calls.

Kinda make sense?

My issue was figuring out how to count the children of children when the keys were unknown ahead of time.
0
Slick812Commented:
OK lets say you do your select, and for that date search, you get two hotels, the first hotel with One room, and and that one room has three "Applicable Rate" arrays in it, but one of three "Applicable Rate" arrays has "Too Few" days, so you need to display only two "Applicable Rate" sets.

The second hotel has Two Rooms, and each of those, has Only One "Applicable Rate" array in it, , BUT the second room "Applicable Rate" array has "Too Few" days in it.

So In the first Hotel case you display the only room and just Two date spreads.

BUT in the second Hotel, since you do not have but one out of two rooms, that have enough days, you not only do NOT display the "Applicable Rate" days for that room , BUT you also have to make it so it does NOT display the short days Room also.
 So you need to access and get counts for the "Applicable Rate" arrays, BEFORE you begin your display, because if your Room and or Hotel do not have any "Applicable Rate" arrays that have enough dates in them, you can not display it.
Does this sound like a place to start for your correct display?
0
erzoolanderAuthor Commented:
Well, here's my process (what I've done so far)...and it's predicated on the idea that any date range being queried can have multiple date/rates for a specific room.

In other words...  there could be a scenario where the hotel has entered:

Rate 1: date-range 12/20/2015 -> 12/25/2015
Rate 2: date-range 12/26/2015 -> 12/30/2015
Rate 3: date-range 12/31/2015 -> 01/02/2016
Rate 4: date-range 1/03/2016 -> 02/13/2016

So let's say someone did a search to find rates for:

12/20/2015 -> 01/04/2016  (nice vacation, huh?)

What my process (currently) does is break the range up into individual dates and iterates through them.

Kind of like...

Is there a rate for 12/20 -> Yes.  Chuck that into the array

Hotel(id) -> Room(id) -> Rate(id) -> Date

Is there a rate for 12/21 -> Yes.  Chuck that into the array

Hotel(id) -> Room(id) -> Rate(id) -> Date2

...etc.

At the end - I have a rather large array filled with results that don't necessarily fit the bill.  Some rooms don't have rates available for the entire duration of the stay...

So what I'm doing then is iterating through the array and counting the subchildren of the rates.

In my example above - the date range being queried is 16 days.  

If there are 16 rate subchildren for a room...I see it as a valid return.  If there are fewer than 16 subchildren of the various rates returned...the result is unset.  At the end - nothing remains but

Hotels -> Rooms -> Rate(ids) -> Whatever

where the subchildren equals the number of dates that has been queried.

Make sense/seem like a decent approach?
0
Slick812Commented:
OK, I did not get the sense that you were -
"If there are fewer than needed dates in the various rates returned...the result is unset."
Altering the array stack, by unsettling some "results".
What I was pointing out, or asking you about, was the counting "method" you use to relate to "rooms", and the "If Test" to determine IF a hotel (top level) array stack should be unset., because you can "If Test" with the count( ) for the Rate array, and unset that Rate array, but if the room array, becomes empty, as in no rate arrays, then just wondering if you go back and test the room arrays (second level), and unset the empty ones. OR keep a record of number rates unset, and if equal to original number in room, then unset that room.

you ask -  "Make sense/seem like a decent approach? ", It sounds like  the overall process may work, , but I can see where some "details" may not be to efficient?
You may can get an a count for the "dates" in a rate, Before that rate is placed into the Room array, and is not enough rates then Do Not Add it, so the latter count analysis could be avoided. May depend on the process of adding the dates in rate.
Sorry if I seem to be reaching, but i can see several ways to go about this, I believe in SQL there is a way to return a "count" of a specific column number of returns, but it may not apply to your select query.
I would think though that from a select query, you can determine the output "number of" dates for a certain Rate, and test to see if that number count is high enough, and then only add to your Hotel array if it is?
0
erzoolanderAuthor Commented:
The problem I had with that approach is what happens when a queried date range spanned across a number of different rates?

Like if Rate 1 is set for date(s) 12-20-2015 to 12-24-2015
Rate 2 is set for 12-25-2015 to 12-30-2015
and Rate 3 is set for 12-31-2015 to 1-05-2016

Doesn't the fact that a query could span across three discreet rate entities necessitate that I treat each day as a unique check?  (i.e., "does day 1 have a rate that applies to it?  does date 2 have a rate that applies to it?" etc etc etc?)

Since each rate has a concrete start and end date...I can't just say....

"select * from rates where querystartdate >= t1.startdate AND queryenddate <= t1.enddate"

with t1 being the rate table...because in the event the query overlapped the end date of one and commencement date of another - it needs to catch both.

?

I'm halfway decent at SQL but not an expert...lol  So maybe there's grouping syntax that I'm unaware of that will allow for a different approach...but the "treat each day as a unique check" is what made sense to me at the moment.

I'm all for optimizing code though and not emotionally attached to what I've done.  :)
0
Ray PaseurCommented:
What if I wanted to stay from December 20 until January 4, and there was a higher rate for New Years Eve?  Would I be able to see / get that rate, even if I got lower rates for some of the other days?
0
Slick812Commented:
Yea - "Since each rate has a concrete start and end date", and you use a join in the SQL to get a specific range, you may need to build the arrays, ahead of time, Nothing comes to mind to use the count() in an SQL and get the results I seem to think you may need. .

But given that you have put some time into this to get your correct grouping, , can you state what you need to do with the groupings that is your result, I have picked up that you can unset any room rate array that has too few dates.  But what now do you need to have an successful display for the hotels - rooms - dates ? ?
0
erzoolanderAuthor Commented:
"What if I wanted to stay from December 20 until January 4, and there was a higher rate for New Years Eve?  Would I be able to see / get that rate, even if I got lower rates for some of the other days? "

Since it iterates through each day in the range and creates an entry into the array for that day - the rate attached to that day (child in the array) is what it found for that specific day.  So - say there was a different rate for NYE - yes - it the rate associated with that day would be the one generated for NYE.

The idea is - 14 days in your reservation query...

Hotel -> Room -> Rate[1] -> X Children (day)  ../ Rate [2] -> X Children (day) etc etc etc.

So if there's 14 days in the span  - there need to be a sum of 14 rate subchildren...with an undefined number of rates (whether it be 1, or 14) - each with the appropriate rate for that specific day.
0
erzoolanderAuthor Commented:
Yea - "Since each rate has a concrete start and end date", and you use a join in the SQL to get a specific range, you may need to build the arrays, ahead of time, Nothing comes to mind to use the count() in an SQL and get the results I seem to think you may need. .

But given that you have put some time into this to get your correct grouping, , can you state what you need to do with the groupings that is your result, I have picked up that you can unset any room rate array that has too few dates.  But what now do you need to have an successful display for the hotels - rooms - dates ? ?

Well, actually someone else gave the answer that fixed my issue earlier on...and I was about to close the thread.  But it's evolved into a discussion of procedure which I don't mind having - because if it refines my process (heck, my process may suck if there's a better way of approaching it) I enjoy the conversation.  Although given how it's evolved beyond the scope of my original question now - I'll give everyone points for contribution.  :)
0
Slick812Commented:
Just my opinion, wish I had time to try and do an SQL example, and see if it does the job needed, but no time now. . . .

The MySQL was set up as a way to "Filter" out just the needed info sets (rows), from thousands of info sets available. There are so many ways in SQL to allow certain rows and block other un-needed rows, and there must be a way to organize and filter in an SQL the things needed for your situation.

Not sure you have tried it, but it looks as though you can use a "GROUP BY" with multiple columns, as your SQL may be similar to -
    select * from rates t1
    left join rooms t2 on t2.id = t1.id
    left join hotels t3 on t3.rid = t2.rid
    WHERE date1 > t1.date2 AND date1 < t1.date3

I might think you could add something like -
     GROUP BY hotels, rooms, date1
with SQL groups you can use the "HAVING" to filter by COUNT(date1) , ONLY using the "date1" in that group, not all of the date1 of that SELECT. However, there may be things I do not know, and this SQL may not work for your kinds of JOIN.

You may ask some in the EE area for SQL or MySQL, if there is a way to do a SELECT, with GROUP BY, or UNION, and get the grouping and and leave out the ones without the needed number of dates.
Good luck.
0
erzoolanderAuthor Commented:
Thanks for all the input.  :)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.