Creation of subclasses

jimctr

Well-known member
Joined
Dec 1, 2011
Messages
52
Programming Experience
Beginner
I am looking to average a number of events occurring over two hour blocks throughout the week, and over every week in the month, across a number of months

For example, I would like a structure such as this MonthOfApril.Week1.HrBlk3, where there will be a total of 12 Block Hours, 4 or 5 weeks depending upon the month, and of course 12 months.

Structure using inheritance doesn't seem to work (unless I am implementing it wrong) as you can inherit from only one source. For example,

Public Class TwoHourBlock 'covers 24 hours, maintaining averages that occur over a weeks period
Public HrBlk1 As UInteger
Public HrBlk2 As UInteger
Public HrBlk3 As UInteger
Public HrBlk4 As UInteger
Public HrBlk5 As UInteger
Public HrBlk6 As UInteger
Public HrBlk7 As UInteger
Public HrBlk8 As UInteger
Public HrBlk9 As UInteger
Public HrBlk10 As UInteger
Public HrBlk11 As UInteger
Public HrBlk12 As UInteger
End Class

Public Class Week1
Inherits TwoHourBlock
End Class

Public Class Week2
Inherits TwoHourBlock
End Class

Public Class Week3
Inherits TwoHourBlock
End Class

Public Class Week4
Inherits TwoHourBlock
End Class

Public Class Week5
Inherits TwoHourBlock
End Class

Public Class Month1
Inherits Week1
Inherits Week2 'This won't work as multiple Inherits not allowed

End Class

How do I do this or should I employ nested structures
 

Dunfiddlin

Well-known member
Joined
Jun 15, 2012
Messages
253
Programming Experience
5-10
What on earth do you mean by average in this context? There's already a perfectly serviceable Date class to handle month. Why add a new one?
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
Nested classes is what you want...

Private MonthOfApril As New Month

Private Class Month
    Public Week1 As New Week
    Public Week2 As New Week
    ...
    
    Private Class Week
        Public HrBlk1 As New HourBlock
        Public HrBlk2 As New HourBlock
        ...
        
        Private Class HourBlock
            ...
        End Class
    End Class
End Class


I have to say however, that this is not really the best way to go about this. Instead you should store all those events in an IEnumerable object, and use Linq or just regular aggregate functions to count your average.

            Dim dt As New DataTable

            dt.Columns.Add(New DataColumn("Date") With {.DataType = GetType(String)})
            dt.Columns.Add(New DataColumn("Number") With {.DataType = GetType(Integer)})

            dt.Rows.Add(New Object() {"25-4-2012", 10})
            dt.Rows.Add(New Object() {"25-4-2012", 10})
            dt.Rows.Add(New Object() {"25-4-2012", 10})
            dt.Rows.Add(New Object() {"25-4-2012", 0})
            dt.Rows.Add(New Object() {"25-4-2012", 0})
            dt.Rows.Add(New Object() {"25-4-2012", 0})
            dt.Rows.Add(New Object() {"25-5-2012", 10})

            Dim Query = From Row As DataRow In dt.Rows Where Date.ParseExact(Row.Item("Date"), "d-M-yyyy", Nothing).Month = 4 Select Row.Field(Of Integer)("Number")

            MessageBox.Show(Query.Average)


This will calculate the average for the column Number for all entries dated in April in the datatable dt. The result is 5.
 
Last edited:

jimctr

Well-known member
Joined
Dec 1, 2011
Messages
52
Programming Experience
Beginner
Thanks. Almost there

Nested classes is what you want...

Private MonthOfApril As New Month

Private Class Month
    Public Week1 As New Week
    Public Week2 As New Week
    ...
    
    Private Class Week
        Public HrBlk1 As New HourBlock
        Public HrBlk2 As New HourBlock
        ...
        
        Private Class HourBlock
            ...
        End Class
    End Class
End Class

One Last thing I am stuck on: This was declared out of the main class as you recommended but changed Privates to Public


Public Class Month
Public Week1 As New Week
Public Week2 As New Week
Public Week3 As New Week
Public Week4 As New Week
Public Week5 As New Week

Public Class Week
Public HrBlk1 As New HourBlock
Public HrBlk2 As New HourBlock
Public HrBlk3 As New HourBlock
Public HrBlk4 As New HourBlock
Public HrBlk5 As New HourBlock
Public HrBlk6 As New HourBlock
Public HrBlk7 As New HourBlock
Public HrBlk8 As New HourBlock
Public HrBlk9 As New HourBlock
Public HrBlk10 As New HourBlock
Public HrBlk11 As New HourBlock
Public HrBlk12 As New HourBlock

Public Class HourBlock
Dim AvgNumberOfEvents As Double
End Class
End Class
End Class

Then in the Main Class,

Dim MonthOfApril As New Month
MonthOfApril.Week1.HrBlk1 = 5 'Does not let me reference AvgNumberOfEvents and assigning to HrBlk1 is Incorrect. Thanks
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
The default access modifier for a variable at class level is Private. Change the Dim for a Public, it should work. You will access it through MonthOfApril.Week1.HrBlk1.AvgNumberOfEvents .
 

Dunfiddlin

Well-known member
Joined
Jun 15, 2012
Messages
253
Programming Experience
5-10
I still don't get why you would approach it in this way. In effect you've created a different variable for each of 720 values and none of them enumerable when this could so easily be handled in a 3D array without any confusion. Block(4,1,1) is every bit as easy to understand as MonthOfApril.Week1.HrBlk1 and allows you to run loops and ranges without difficulty. And where does the data come from? It will be a nightmare to feed values to 720 individual locations!
 

jimctr

Well-known member
Joined
Dec 1, 2011
Messages
52
Programming Experience
Beginner
I will need to look at your suggestions. I'm pretty new to VB and want to look for the simplest solution. The data is generated from time stamped camera images (extracting exif data which I have already done) and I want to see if there is any statistical correlation between time of day and number of encounters(activity level). I want to be able to see this on a weekly and monthly basis.

Bar graphs will be generated using Fusion Charts. I am time slicing a day into 12 two hour parts, but then summing up the time slices on a weekly basis. So Monday thru Sunday for a particular week, I will total up, for example, all encounters between 12AM and 2PM. This will be done for all 12 time slices. This will be assigned to Wk1 through Wk5 of a particular month, realizing that there are partial weeks in a month.

I will then sum the time slices on a monthly level, so week1.HrBlk1.TotalEvents + week2.HrBlk1.TotalEvents + ..., down the line for all the HrBlks.

From these totals daily and weekly averages, sd deviations and correlations can be generated.

Later I will also consider the independent variables Pressure and Temperature (also stored in Exif), and see how well they correlate with number of encounters.
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
Then what you need to do is create one giant table with everything in it as your data source. Create a datatable, add some columns (ImagePath, ImageDateTime, Pressure, Temperature, etc), and query that datatable to extract subsets, like I did above. This is 1000x better that using that custom structure of yours, and virtually any calculation you need will be a one-liner like the average above, instead of many many lines of code just to get around your structure.

Have a look here to see 101 examples of what you can do with Linq: http://msdn.microsoft.com/en-us/vstudio/bb688084
 

jimctr

Well-known member
Joined
Dec 1, 2011
Messages
52
Programming Experience
Beginner
Hi Herman:

I am attempting the Linq query from your example and I want to find how many distinct years are located in the date column

Dim NYears = (From Row As DataRow In dt.Rows Where Date.ParseExact(Row.Item("Date"), "yyyy:MM:dd", Nothing).Year Select Row.Field(Of String)("Date")).Distinct
Dim CountYears As Integer = NYears.Count

I would expect the CountYears to be 2, since 2011 and 2012 dates are included; however, this is getting all distinct dates in the list irrespective of year and so Countyears is 10. The person will not know what years are covered in the file he loads. Hence, I don't have the .Year = to any particular value.

Your help would be greatly appreciated. Thanks
 

jimctr

Well-known member
Joined
Dec 1, 2011
Messages
52
Programming Experience
Beginner
This is the answer

Dim NYears = (From Row As DataRow In dt.Rows Select Date.ParseExact(Row.Item("Date"), "yyyy:MM:dd", Nothing).Year).Distinct

I see, Where was expecting some assignment via =
 

Herman

Well-known member
Joined
Oct 18, 2011
Messages
882
Location
Montreal, QC, CA
Programming Experience
10+
It would go something like this:

Dim QueryYears As IEnumerable(Of Date) = From Row As DataRow In dt.Rows Group Row By Year = Date.ParseExact(Row.Item("Date"), "yyyy:MM:dd", Nothing).Year Into Group

Dim NumberOfUniqueYears As Integer = QueryYears.Count()


Hehe your solution works too, little bit less code too..
 
Top Bottom