Link to home
Start Free TrialLog in
Avatar of erzoolander
erzoolander

asked on

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!
Avatar of Ray Paseur
Ray Paseur
Flag of United States of America image

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

Avatar of erzoolander
erzoolander

ASKER

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.  :)
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?
ASKER CERTIFIED SOLUTION
Avatar of Brian Tao
Brian Tao
Flag of Taiwan, Province of China image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.
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?
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?
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?
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.  :)
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?
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 ? ?
"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.
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.  :)
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for all the input.  :)