none
Sorting a list made of a structure RRS feed

  • Question

  • Hello everybody,

    I Created a list  , and its elements are made of a structure of 3 fields.

    I would like to sort the list by each of the 3 fields, of different types. like: Int. string, Boolean/

    With 3 different sort subroutines it is easy to do it.

    My question: Can I do it with ONE sort subroutine, by sending a parameter that will imply 

        which type of sort to do? Or another way?

    I hope I was clear.

      Thanks in advance for your responses.

         M.M


    All things are difficult before they are easy. (unknown)

    Tuesday, October 10, 2017 9:59 PM

Answers

  • Hello Frank,

       With my poor knowledge in classes, I can not agree that a structure is the same as a class..

    Maybe  it's time for me to learn classes. Do you recommend? I am sure - yes.

    Feel free to answer when you have time. I am not in hurrying.

    And thanks fro your efforts,

         Moshe.


    All things are difficult before they are easy. (unknown)

    You're quite welcome and I hope you get something out of the following to help:

    Moshe,

    Sorry for the incongruous dialogue, but work has to come first and I’m sure you understand.

    We’ll start this by a discussion, albeit a short one, of classes compared with structures. As Cor said, in use they’re similar (but not the same). Underlying that though, they’re a fair amount different. You can’t really have a discussion about the differences until you have a good grasp of value types compared to reference types. I hope you’ll take a few minutes to peruse that article; it’s worth the read.

    A structure is a value type and a class is a reference type. Does that matter? Well – in some ways, not much but in other ways yes … quite a lot.

    As much as anything, a reference type is an address to some location in memory. More specifically, it’s an address on the managed heap (memory) rather than on the stack.

    I’m sure that’s about as clear as mud, but one of the great accomplishments of dotNET is that we developers* don’t have to deal with memory management; the framework will take care of it, but we do have to be mindful of it and that’s what prompted this discussion.

     

    (*The asterisk is because I’m not a developer, not really – I’m a mechanical engineer who likes this stuff so I’m just an amateur.)

     

    The choice between using a structure as compared to a class is noteworthy. Let’s see what Microsoft has to say about that decision in this article.

    In that article please notice this in particular:

     

    As a rule of thumb, the majority of types in a framework should be classes. There are, however, some situations in which the characteristics of a value type make it more appropriate to use structs.

    CONSIDER defining a struct instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.

    X AVOID defining a struct unless the type has all of the following characteristics:

    1. It logically represents a single value, similar to primitive types (int, double, etc.).
    2. It has an instance size under 16 bytes.
    3. It is immutable.
    4. It will not have to be boxed frequently.

    In all other cases, you should define your types as classes.

     

     

    The concept of a structure is a great one; in a lot of ways it’s much more efficient than a class.

    With a class, once an instance of it is “de-referenced”, it can no longer be used, but it hasn’t gone away yet; not really. That’s where the memory manager’s logic kicks in to know what to do and when to do it. That’s what Cor was talking about earlier in mentioning the Garbage Collector.

    At some point or another you’ll also be dealing with unmanaged resources and when you do, let’s talk again; it would dilute this discussion too much to go into it now.

    A structure, unlike a class, doesn’t live on after it’s de-referenced. In that quote from MSDN earlier, notice that one of the suggested criteria is “short-lived” and that does make sense. Once that instance of the structure loses scope, it’s gone. Yes gone gone! *POOF*

    The stack is said to be “unwound”; that instance literally no longer exists. That makes it cleaner and easier (and usually faster because of it), but you have to pit that against the potential issues with using a structure (as opposed to a class) as shown earlier.

    Well how can we know?

    If you want to really convolute things, consider this: An array of instances of a structure where the members of the structure are all reference types (like strings). That’ll make you cross-eyed to think about it! ;-)

    It is a lot to keep up with.

    When I see a string, in particular, I’m wary of using it in a structure until I know more about that string. Strings are weird animals.

    First, please look at what it shows for the “nominal allocation” of these primitive types and scroll down to find “string” in that list:

     

    https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/data-types/data-type-summary

     

    That makes sense too. A string can be one character long or the entire contents of an encyclopedia! Well, ok – a small encyclopedia but you get the point. How can it know how much to allocate, let alone what to do if it changes!?

    This is one reason why strings are “weird” and also why they’re immutable (read-only … you can’t change a string).

    “Sure I can Frank. I change them all the time!”

    Actually, no you didn’t; you created a new one each time and you abandoned the old one. Even though this is a bit off-topic, read some of this MSDN document and scroll down to the section entitled “String versus SecureString” and you’ll see this:

     

    An instance of the System.String class is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created, and it is not possible to predict when the instance will be deleted from computer memory. Because System.String instances are immutable, operations that appear to modify an existing instance actually create a copy of it to manipulate.

     

    That doesn’t sound like something you’d want in a structure then does it! ;-)

    So what happens if you use a structure? Will the program crash (as with a stack overflow exception)?

    Ehh, maybe but I doubt it. It’s possible, but that’s not so much the issue here; performance is the issue. Do some research on your own about these things and look for such terms as boxing/unboxing (just one of many performance hits) like this article on CodeProject. One I’ve had around for a while is this one; it’s a little confusing at first but bookmark it for later maybe.

     

    *****

     

    The specifics of your situation can be dealt with a number of ways. One way is by implementing the IComparable interface like I did earlier this morning. How do you know which comes before another?

    I mean with anything. Which is less? 1 or 2?

    “1”

    “Are you sure? Can you prove it? How do you know?”

    With classes, you know because you’ve told it to be so and you do that by implementing the CompareTo method in the IComparable interface. That’s how you know you: Your class; your instructions!

    Think about something here: When the class is asked to look at this instance and compare it to that instance and make an assessment about which one comes first, what CompareTo is really telling it is to yield a result of 1, 0, or -1:

     

    Value

    Meaning

    Less than zero

    This instance precedes obj in the sort order.

    Zero

    This instance occurs in the same position in the sort order as obj.

    Greater than zero

    This instance follows obj in the sort order.

     

    The result now tells it that it’s less than, equal to, or greater than the other instance. That’s a simple notion but one that seem to befuddle us at first. ;-)

    Using the IComparable interface, you can sort the class easily (and quite quickly too) but it’s pretty rigid isn’t it? What if you want it this way sometimes or that way some other times?

    That’s where LINQ (like I showed in the second example) or using lambda expressions (like IR showed last night) can come in very handy. They take a while to get a good handle on but it’s worth the learning experience.

    Also, like I mentioned last night, a DataTable coupled with a BindingSource is yet another way. The BindingSource has a “Sort” property that’s pretty straightforward.

    With dotNET and most other well-developed programming languages, there are many ways to accomplish anything.

     

    *****

     

    The answer to your question, if it’s not been answered here by someone (me included) already is in yourself.

    Get through some of those articles, try them out and if you get stuck then let’s start again.

    :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Marked as answer by Head_one Wednesday, October 11, 2017 6:38 PM
    Wednesday, October 11, 2017 4:49 PM
  • Hello Frank,
       Thank you for writing me a  dotNET mini Manual.
      I read  and have some knowledge about Value types and reference types.
      It is good you added some links, to learn from. I will do it soon.

      Earlier ,IronRazers replied me, and attached a code with a small bug.
      The code works, no run time error, but nothing happens.
      I think he forgot to close a class with "End class". This I will do next.

    I am sure, I can learn from his code.

     
      Next to it, I will read the links you sent.

      Again, thanks for you long explanation. It will help for sure.

        Best regards.

            Moshe.

               

    All things are difficult before they are easy. (unknown)


    You're welcome. :)

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Marked as answer by Head_one Wednesday, October 11, 2017 6:38 PM
    Wednesday, October 11, 2017 6:29 PM
  • Ray,

    Why are you showing code which is in fact wrong to use. 

    He uses a struct in his code, which has more change on memory overflow then when were used classes. 

    I've seen many persons here who asked for help. But never gave code from which I knew it was basically wrong because an asker was to lazy to learn the benefit of classes above structures, it takes less time, than the time you've spend to make the code. 

    After a while the same person tells he got a memory overflow in his program which he made with code which he got from IronRazerz and by that giving for others the impression you did not know that.

     


    Success
    Cor

     My point was not about using a Class or Structure,  my main point was about creating and using an Enumeration to pass to a single sorting sub/function.  That is what Head_one was asking about.  He asked...

     "My question: Can I do it with ONE sort subroutine, by sending a parameter that will imply which type of sort to do? Or another way?"

     I do not disagree,  it would be better to use a Class instead of a Structure whenever you can.  I am positive that if someone was to ever look back through my posts from over the years,  they would find where i have recommended the use of a Class instead of a Structure but,  they would never find me recommending the reverse.


    If you say it can`t be done then i`ll try it

    • Marked as answer by Head_one Wednesday, October 11, 2017 6:38 PM
    Wednesday, October 11, 2017 6:34 PM

All replies

  • Hello everybody,

    I Created a list  , and its elements are made of a structure of 3 fields.

    I would like to sort the list by each of the 3 fields, of different types. like: Int. string, Boolean/

    With 3 different sort subroutines it is easy to do it.

    My question: Can I do it with ONE sort subroutine, by sending a parameter that will imply 

        which type of sort to do? Or another way?

    I hope I was clear.

      Thanks in advance for your responses.

         M.M


    All things are difficult before they are easy. (unknown)

    It sounds like you might want to use a class (rather than a structure), but to answer your question: You can use LINQ to do what what want. It's very flexible.

    Do you have a few examples? If so, I'll put something more specific together.

    ***** EDIT *****

    You might also think about setting up a DataTable along with a BindingSource. If you do that, you can then use the BindingSource's .Filter property for it.


    "A problem well stated is a problem half solved.” - Charles F. Kettering



    Tuesday, October 10, 2017 10:13 PM
  • Hello everybody,

    I Created a list  , and its elements are made of a structure of 3 fields.

    I would like to sort the list by each of the 3 fields, of different types. like: Int. string, Boolean/

    With 3 different sort subroutines it is easy to do it.

    My question: Can I do it with ONE sort subroutine, by sending a parameter that will imply 

        which type of sort to do? Or another way?

    I hope I was clear.

      Thanks in advance for your responses.

         M.M


    All things are difficult before they are easy. (unknown)

    I showed an example of filtering, not sorting, but with LINQ you can accomplish either one easily.

    Sorry for the confusion...


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Tuesday, October 10, 2017 10:45 PM
  •  Not 100% sure if this is what you are asking but,  maybe just create an Enum that has the sort modes you want to implement.  Then add a parameter of the Enum type In you sorting Sub/Function.  Then you can pass the sorting type you want to a single Sub/Function.  For example....

    Public Class Form1
        Private StructList As New List(Of MyStruct)
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            StructList.Add(New MyStruct("Joe Blow", 32, True, Now.AddDays(-100)))
            StructList.Add(New MyStruct("Zack Black", 19, True, Now.AddDays(-90)))
            StructList.Add(New MyStruct("Amy Reine", 47, False, Now.AddDays(-250)))
            StructList.Add(New MyStruct("Linda Lewis", 22, True, Now.AddDays(-33)))
            StructList.Add(New MyStruct("Greg Zippy", 31, False, Now.AddDays(-63)))
            RadioButton_Name.Checked = True
            SortList(SortMode.Name)
        End Sub
    
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            If RadioButton_Name.Checked Then
                SortList(SortMode.Name)
            ElseIf RadioButton_Age.Checked Then
                SortList(SortMode.Age)
            ElseIf RadioButton_Donated.Checked Then
                SortList(SortMode.Donated)
            Else
                SortList(SortMode.Date)
            End If
        End Sub
    
        Private Sub SortList(sortmode As SortMode)
            Dim srtList As List(Of MyStruct) = Nothing
            Select Case sortmode
                Case SortMode.Name
                    StructList = StructList.OrderBy(Function(x) x.Name).ToList
                Case SortMode.Age
                    StructList = StructList.OrderBy(Function(x) x.Age).ToList
                Case SortMode.Donated
                    StructList = StructList.OrderBy(Function(x) x.Donated).ToList
                Case SortMode.Date
                    StructList = StructList.OrderBy(Function(x) x.JoinDate).ToList
            End Select
            ListBox1.DataSource = StructList 'this is just to show the data for testing
        End Sub
    End Class
    
    'Simulates your structure with 3 different type members String, Integer, and Boolean
    Public Structure MyStruct
        Public Name As String
        Public Age As Integer
        Public Donated As Boolean
        Public JoinDate As Date
    
        Public Sub New(pName As String, pAge As Integer, pDonated As Boolean, pJoinDate As Date)
            Name = pName
            Age = pAge
            Donated = pDonated
            JoinDate = pJoinDate
        End Sub
    
        Public Overrides Function ToString() As String
            Return Name & " : " & Age.ToString & " : " & Donated.ToString & " : " & JoinDate.ToShortDateString
        End Function
    End Structure
    
    'A sorting mode Enumeration that is used to pass to the sorting Sub/Function
    Public Enum SortMode As Integer
        Name = 0
        Age = 1
        Donated = 2
        [Date] = 3
    End Enum
    
     

     


    If you say it can`t be done then i`ll try it

    Tuesday, October 10, 2017 11:39 PM
  • Hello,

    Thanks for you reply. It will take me time to check and understand  the code you have written, but I watched the picture form, and see that it does EXACTLY what I was asking for.

    Here it is 03:10 and to late to check now you code. I will check it soon, and try to learn it . Anyway, You gave a good solution.

       Thank you very much, and all the best.

                                                    Moshe.


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 12:09 AM
  • Hello Frank,

    1. I do not uses classes, although I know the principles of it.

        I do not know enough to use it.

    2. I do not know what is : LINQ, DATATABLE and BindingSource.

    3. I have learn  a lot  more in Vb.Net, and  prefer not  to  learn other      subjects.

    4. If you want, I can display  the code I wrote.

           Thanks,

                Moshe.


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 12:39 AM
  • Hello Frank,

    1. I do not uses classes, although I know the principles of it.

        I do not know enough to use it.

    2. I do not know what is : LINQ, DATATABLE and BindingSource.

    3. I have learn  a lot  more in Vb.Net, and  prefer not  to  learn other      subjects.

    4. If you want, I can display  the code I wrote.

           Thanks,

                Moshe.


    All things are difficult before they are easy. (unknown)

    If you want then tomorrow we can pull all these things apart.

    I won't be here until after noon (U.S. CDT) but as far as I know right now, I should be here afterward.

    The BindingSource is particularly interesting. In fact, you can use it to sort and filter (and/or both) using "English like" terms.

    Let me know tomorrow if you're interested in we'll go from there.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, October 11, 2017 12:49 AM
  • Hello Frank,

    I am interesting of course, but take your time.

    I tried to attach the code, but a message appeared

    and said that only 60,000 chars are allowed.

    The code is much less. only 78 rows incl. empty rows.

    Thanks and all the Best,
                           Moshe.
    ---------------------------------------------


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 1:13 AM
  • Hi Head_one,

    Put some code by click this icon.

    And select vb.net language.

    Best Regards,

    Cherry


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, October 11, 2017 6:58 AM
    Moderator
  • Attached my code + form Picture
       Thank you very much.
                    Moshe.
    
    Public Class Form1
        Structure List_Rec
            Dim Country As String
            Dim Continent As String
            Dim Population As Integer
        End Structure
    
        Dim My_List As New List(Of List_Rec)
    
        Dim Country_Arr() As String = {"Germany", "Usa", "Romania", "Israel", "Kanada"}
        Dim Continent_Arr() As String = {"Europe", "America", "Europe", "Asia", "America"}
        Dim Pop_arr() As Integer = {82, 330, 23, 8, 37}
        Dim Temp As List_Rec
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            For n = 0 To 4
                Temp.Country = Country_Arr(n)
                Temp.Continent = Continent_Arr(n)
                Temp.Population = Pop_arr(n)
                My_List.Add(Temp)
            Next
    
        End Sub
    
        Private Sub Display1_but_Click(sender As System.Object, e As System.EventArgs) Handles Display1_but.Click
            Display_list(My_List, "Unsorted:")
        End Sub
    
        Private Sub Display3_But_Click(sender As System.Object, e As System.EventArgs) Handles Display3_But.Click
            Sort_by_country(My_List)
            Display_list(My_List, "Sorted by country:")
        End Sub
    
        Private Sub Display_list(ByVal my_list As List(Of List_Rec), ByVal Hdr As String)
            Text1.AppendText(" " & vbCrLf)
            Text1.AppendText(Hdr & vbCrLf)
            For Each item In my_list
                Text1.AppendText(item.Country & vbTab & item.Continent & vbTab & item.Population & vbCrLf)
            Next
    
        End Sub
    
        Private Sub Sort_by_country(ByRef my_list As List(Of List_Rec))
            Dim i As Integer
            Dim j As Integer
    
            If My_List.Count > 0 Then
                For i = 0 To My_List.Count - 2
                    For j = i + 1 To My_List.Count - 1
                        If My_List(j).Country < My_List(i).Country Then
                            Temp = My_List(i)
                            My_List(i) = My_List(j)
                            My_List(j) = Temp
                        End If
                    Next j
                Next i
            End If
        End Sub
    
        Private Sub Exit_but_Click(sender As System.Object, e As System.EventArgs) Handles Exit_but.Click
            Close()
        End Sub
        'FOR DEBUG ONLY
        'Private Sub Display_List(ByVal Hdr As String)
        '    Dim obj As List_Rec
        '    List1.Items.Clear()
        '    List1.Items.Add(Hdr)
        '    List1.Items.Add(" ")
    
        '    For Each obj In My_List
        '        With obj
        '            List1.Items.Add(.Country & "   " & .Continent)
    
        '        End With
        '    Next
        'End Sub
    End Class
    
    


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 8:10 AM
  • Ray,

    Why are you showing code which is in fact wrong to use. 

    He uses a struct in his code, which has more change on memory overflow then when were used classes. 

    I've seen many persons here who asked for help. But never gave code from which I knew it was basically wrong because an asker was to lazy to learn the benefit of classes above structures, it takes less time, than the time you've spend to make the code. 

    After a while the same person tells he got a memory overflow in his program which he made with code which he got from IronRazerz and by that giving for others the impression you did not know that.

     


    Success
    Cor

    Wednesday, October 11, 2017 10:49 AM
  • Hello Cor,
      Thanks for your reply.
       I use a structure, not a class, not because I am lazy. I just do not know classes well.
    Maybe, your answer will encourage me to learn classes extensively.
    I did not say I have a menory overflow.

    I said: When running IronRazerz's code, nothing happends on screen, 

    although  there is no runtime error.

       Thanks.

            Moshe.


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 11:54 AM
  • Moshe,

    Try this so to prove to yourself that it works, then let's talk about all of it in a few hours:

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
           
            Dim giList As New List(Of GeographicInfo)
    
            With giList
                .Add(New GeographicInfo("Germany", "Europe", 82))
                .Add(New GeographicInfo("USA", "North America", 330))
                .Add(New GeographicInfo("Romania", "Europe", 23))
                .Add(New GeographicInfo("Israel", "Asia", 8))
                .Add(New GeographicInfo("Canada", "North America", 37))
            End With
    
            giList.Sort()
    
            Dim sb As New System.Text.StringBuilder
    
            For i As Integer = 0 To giList.Count - 1
                sb.AppendLine(giList(i).ToString)
    
                If i < giList.Count - 1 Then
                    sb.AppendLine()
                    sb.AppendLine("----------")
                    sb.AppendLine()
                End If
            Next
    
            MessageBox.Show(sb.ToString)
    
            Stop
    
        End Sub
    End Class
    
    
    
    
    
    Public Class GeographicInfo
        Implements IComparable
        Implements IComparable(Of GeographicInfo)
    
        Private _country As String
        Private _continent As String
        Private _population As Integer
    
        Public Sub New(ByVal country As String, _
                       ByVal continent As String, _
                       ByVal population As Integer)
    
            ' This shouldn't be done this way... let's discuss
            ' it but for my example, it'll do
    
            _country = country.Trim
            _continent = continent.Trim
            _population = population
    
        End Sub
    
        Public ReadOnly Property Continent As String
            Get
                Return _continent
            End Get
        End Property
    
        Public ReadOnly Property Country As String
            Get
                Return _country
            End Get
        End Property
    
        Public ReadOnly Property Population As Integer
            Get
                Return _population
            End Get
        End Property
    
        Public Overrides Function ToString() As String
            Return String.Format("{0} | {1} | {2:n0}", _continent, _country, _population)
        End Function
    
        Public Function CompareTo(ByVal obj As Object) As Integer _
            Implements IComparable.CompareTo
    
            If obj Is Nothing Then
                Return 1
            End If
    
            Dim other As GeographicInfo = Nothing
    
            If TypeOf obj Is GeographicInfo Then
                other = CType(obj, GeographicInfo)
            End If
    
            If other Is Nothing Then
                Throw New ArgumentException("obj is not a GeographicInfo")
            End If
    
            Return CompareTo(other)
    
        End Function
    
        Public Function CompareTo(ByVal other As GeographicInfo) As Integer _
            Implements IComparable(Of GeographicInfo).CompareTo
    
            If other Is Nothing Then
                Return 1
            End If
    
            Dim result As Integer = _continent.CompareTo(other._continent)
    
            If result <> 0 Then
                Return result
            End If
    
            result = _country.CompareTo(other._country)
    
            If result <> 0 Then
                Return result
            End If
    
            result = Me._population.CompareTo(other._population)
    
            If result <> 0 Then
                Return result
            End If
    
            Return result
    
        End Function
    End Class

    I have to attend to "real work" first -- I'm sure you understand.

    I'll be back though, then let's pull it all apart. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, October 11, 2017 12:16 PM
  • Hello Cor,
      Thanks for your reply.
       I use a structure, not a class, not because I am lazy. I just do not know classes well.
    Maybe, your answer will encourage me to learn classes extensively.
    I did not say I have a menory overflow.

    I said: When running IronRazerz's code, nothing happends on screen, 

    although  there is no runtime error.

       Thanks.

            Moshe.


    All things are difficult before they are easy. (unknown)

    Moshe,

    There is not much difference between a structure and a class in use. 

    The main difference is that with a class you construct every time a new object which is placed in the heap, while a structure is not constructed but a piece of date direct in the main part of the memory of the program. If an (class) object has not anymore a reference too it. It is automatically released and the memory is made freeed by the Garbage collector. A struct stays forever in memory until the program stops. Therefore the advice is not to use it for data which is more than 18bytes.

    To use it, means by the code of IronRazer that you use Class instead of Structure. 

     


    Success
    Cor

    Wednesday, October 11, 2017 12:30 PM
  • Hello Frank,

    1. Thanks for the code. I tried it and it works fine.

    2. I noticed you have used a new class.

         I do not use classes yet, although I understand  how it works.

    3. The main idea was to use the same sort procedure for all 3 fields:

        Country, Continent and population.

        So I expected to see 3 Radio buttons  or 3 buttons, from which I can

        select the type of sorting the table.

     I will be close my computer next hours.

        Thanks,

              Moshe.


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 1:28 PM
  • I do not use classes yet...

    Go back to your structure please and do the following:

    Change the word "Structure" to "Class" in two places. That may not be the best way forward, but it certainly is a valid class.

    In mine from earlier (and the one I'll post in a minute) I'm using a constructor. Even though your constructor isn't explicit, it's there - dotNET put it there for you because you didn't.

    We already have a lot of things to talk about but as much as anything, I'd like to plant the ideas and get you to research them, try them, think about them and you'll be amazed at how much you already know about them (and how much there is yet to know). ;-)

    *****

    The main idea was to use the same sort procedure for all 3 fields...

    I'm not sure what you mean, not really, but here's one way that you might try even if it's not what you want:

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
            For i As Integer = 0 To [Enum].GetValues(GetType(GeographicInfo2.SortField)).Length - 1
                Dim value As GeographicInfo2.SortField = DirectCast(i, GeographicInfo2.SortField)
    
                If value <> GeographicInfo2.SortField.NA Then
                    Dim data As GeographicInfo2() = GeographicInfo2.GetData(value)
                    ShowData(data, value)
                End If
            Next
    
            Stop
    
        End Sub
    
        Private Sub _
            ShowData(ByVal data() As GeographicInfo2, _
                     ByVal orderBy As GeographicInfo2.SortField)
    
            If data IsNot Nothing Then
                Dim sb As New System.Text.StringBuilder
    
                For i As Integer = 0 To data.Length - 1
                    Dim instance As GeographicInfo2 = data(i)
    
                    sb.AppendLine(instance.ToString)
    
                    If i < data.Length - 1 Then
                        sb.AppendLine()
                        sb.AppendLine("----------")
                        sb.AppendLine()
                    End If
                Next
    
                sb.Remove(sb.Length - 2, 2)
                MessageBox.Show(sb.ToString, "Ordered By: " _
                                & orderBy.ToString)
            End If
    
        End Sub
    End Class
    
    
    
    
    
    Public Class GeographicInfo2
        Public Enum SortField
            NA
            NaturalOrder
            Country
            Continent
            Population
        End Enum
    
        Private _country As String
        Private _continent As String
        Private _population As Integer
    
        Private Sub New(ByVal country As String, _
                        ByVal continent As String, _
                        ByVal population As Integer)
    
            ' Now that this constructor is private, the
            ' following is perfectly valid because before
            ' the code ever gets here, I'll have validated
            ' the data.
    
            ' In this case, I'm going to use an initializer
            ' so if there's an error here then it's surely
            ' my own fault! ;-)
    
            _country = country.Trim
            _continent = continent.Trim
            _population = population
    
        End Sub
    
        Public ReadOnly Property Continent As String
            Get
                Return _continent
            End Get
        End Property
    
        Public ReadOnly Property Country As String
            Get
                Return _country
            End Get
        End Property
    
        Public ReadOnly Property Population As Integer
            Get
                Return _population
            End Get
        End Property
    
        Public Shared Function _
            GetData(ByVal order As SortField) As GeographicInfo2()
    
            Dim retVal() As GeographicInfo2 = Nothing
    
            If order = SortField.NA Then
                Throw New ArgumentException("The order must be set.")
    
            Else
                Dim data As IEnumerable(Of GeographicInfo2) = InitializeData()
                Dim qry As IEnumerable(Of GeographicInfo2) = Nothing
    
                Select Case order
                    Case SortField.Continent
                        qry = From gi As GeographicInfo2 In data _
                              Order By gi.Continent
    
                    Case SortField.Country
                        qry = From gi As GeographicInfo2 In data _
                              Order By gi.Country
    
                    Case SortField.NaturalOrder
                        qry = From gi As GeographicInfo2 In data
    
                    Case SortField.Population
                        qry = From gi As GeographicInfo2 In data _
                              Order By gi.Population
                End Select
    
                If qry IsNot Nothing Then
                    retVal = qry.ToArray
                End If
            End If
    
            Return retVal
    
        End Function
    
        Public Overrides Function ToString() As String
            Return String.Format("{0} | {1} | {2:n0}", _continent, _country, _population)
        End Function
    
        Private Shared Function InitializeData() As IEnumerable(Of GeographicInfo2)
    
            Dim list As New List(Of GeographicInfo2)
    
            With list
                .Add(New GeographicInfo2("Germany", "Europe", 82))
                .Add(New GeographicInfo2("USA", "North America", 330))
                .Add(New GeographicInfo2("Romania", "Europe", 23))
                .Add(New GeographicInfo2("Israel", "Asia", 8))
                .Add(New GeographicInfo2("Canada", "North America", 37))
            End With
    
            Return list.ToArray
    
        End Function
    End Class

    I'll be back in a few hours. I have a deadline looming but I'm nearly there already.

    I'll put some links together and I'll be back. ;-)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, October 11, 2017 2:33 PM
  • Hello Frank.

    1. I changed "Structure" to "Class", as you asked.

        I got many errors because I had to change "Private" to "Public", in many places.

       I did, but it still does not work.

    2. The best and shortest way, is to send you my original code, and you make all required changes,  if you do not mind.

    Just tell me - and I send.

    3. Meanwhile,  I will check your last code.

       Many thanks,

                Moshe. 

      


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 3:23 PM
  • Hello Frank.

    1. I changed "Structure" to "Class", as you asked.

        I got many errors because I had to change "Private" to "Public", in many places.

       I did, but it still does not work.

    2. The best and shortest way, is to send you my original code, and you make all required changes,  if you do not mind.

    Just tell me - and I send.

    3. Meanwhile,  I will check your last code.

       Many thanks,

                Moshe. 

      


    All things are difficult before they are easy. (unknown)

    I only meant that superficially, a class and a structure are similar.

    Under the hood is where the differences are so be patient for a while please - I'm just out of time, I'm not trying to be rude.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Wednesday, October 11, 2017 3:30 PM
  • Hello Frank,

       With my poor knowledge in classes, I can not agree that a structure is the same as a class..

    Maybe  it's time for me to learn classes. Do you recommend? I am sure - yes.

    Feel free to answer when you have time. I am not in hurrying.

    And thanks fro your efforts,

         Moshe.


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 4:05 PM
  • Hello Frank,

       With my poor knowledge in classes, I can not agree that a structure is the same as a class..

    Maybe  it's time for me to learn classes. Do you recommend? I am sure - yes.

    Feel free to answer when you have time. I am not in hurrying.

    And thanks fro your efforts,

         Moshe.


    All things are difficult before they are easy. (unknown)

    You're quite welcome and I hope you get something out of the following to help:

    Moshe,

    Sorry for the incongruous dialogue, but work has to come first and I’m sure you understand.

    We’ll start this by a discussion, albeit a short one, of classes compared with structures. As Cor said, in use they’re similar (but not the same). Underlying that though, they’re a fair amount different. You can’t really have a discussion about the differences until you have a good grasp of value types compared to reference types. I hope you’ll take a few minutes to peruse that article; it’s worth the read.

    A structure is a value type and a class is a reference type. Does that matter? Well – in some ways, not much but in other ways yes … quite a lot.

    As much as anything, a reference type is an address to some location in memory. More specifically, it’s an address on the managed heap (memory) rather than on the stack.

    I’m sure that’s about as clear as mud, but one of the great accomplishments of dotNET is that we developers* don’t have to deal with memory management; the framework will take care of it, but we do have to be mindful of it and that’s what prompted this discussion.

     

    (*The asterisk is because I’m not a developer, not really – I’m a mechanical engineer who likes this stuff so I’m just an amateur.)

     

    The choice between using a structure as compared to a class is noteworthy. Let’s see what Microsoft has to say about that decision in this article.

    In that article please notice this in particular:

     

    As a rule of thumb, the majority of types in a framework should be classes. There are, however, some situations in which the characteristics of a value type make it more appropriate to use structs.

    CONSIDER defining a struct instead of a class if instances of the type are small and commonly short-lived or are commonly embedded in other objects.

    X AVOID defining a struct unless the type has all of the following characteristics:

    1. It logically represents a single value, similar to primitive types (int, double, etc.).
    2. It has an instance size under 16 bytes.
    3. It is immutable.
    4. It will not have to be boxed frequently.

    In all other cases, you should define your types as classes.

     

     

    The concept of a structure is a great one; in a lot of ways it’s much more efficient than a class.

    With a class, once an instance of it is “de-referenced”, it can no longer be used, but it hasn’t gone away yet; not really. That’s where the memory manager’s logic kicks in to know what to do and when to do it. That’s what Cor was talking about earlier in mentioning the Garbage Collector.

    At some point or another you’ll also be dealing with unmanaged resources and when you do, let’s talk again; it would dilute this discussion too much to go into it now.

    A structure, unlike a class, doesn’t live on after it’s de-referenced. In that quote from MSDN earlier, notice that one of the suggested criteria is “short-lived” and that does make sense. Once that instance of the structure loses scope, it’s gone. Yes gone gone! *POOF*

    The stack is said to be “unwound”; that instance literally no longer exists. That makes it cleaner and easier (and usually faster because of it), but you have to pit that against the potential issues with using a structure (as opposed to a class) as shown earlier.

    Well how can we know?

    If you want to really convolute things, consider this: An array of instances of a structure where the members of the structure are all reference types (like strings). That’ll make you cross-eyed to think about it! ;-)

    It is a lot to keep up with.

    When I see a string, in particular, I’m wary of using it in a structure until I know more about that string. Strings are weird animals.

    First, please look at what it shows for the “nominal allocation” of these primitive types and scroll down to find “string” in that list:

     

    https://docs.microsoft.com/en-us/dotnet/visual-basic/language-reference/data-types/data-type-summary

     

    That makes sense too. A string can be one character long or the entire contents of an encyclopedia! Well, ok – a small encyclopedia but you get the point. How can it know how much to allocate, let alone what to do if it changes!?

    This is one reason why strings are “weird” and also why they’re immutable (read-only … you can’t change a string).

    “Sure I can Frank. I change them all the time!”

    Actually, no you didn’t; you created a new one each time and you abandoned the old one. Even though this is a bit off-topic, read some of this MSDN document and scroll down to the section entitled “String versus SecureString” and you’ll see this:

     

    An instance of the System.String class is both immutable and, when no longer needed, cannot be programmatically scheduled for garbage collection; that is, the instance is read-only after it is created, and it is not possible to predict when the instance will be deleted from computer memory. Because System.String instances are immutable, operations that appear to modify an existing instance actually create a copy of it to manipulate.

     

    That doesn’t sound like something you’d want in a structure then does it! ;-)

    So what happens if you use a structure? Will the program crash (as with a stack overflow exception)?

    Ehh, maybe but I doubt it. It’s possible, but that’s not so much the issue here; performance is the issue. Do some research on your own about these things and look for such terms as boxing/unboxing (just one of many performance hits) like this article on CodeProject. One I’ve had around for a while is this one; it’s a little confusing at first but bookmark it for later maybe.

     

    *****

     

    The specifics of your situation can be dealt with a number of ways. One way is by implementing the IComparable interface like I did earlier this morning. How do you know which comes before another?

    I mean with anything. Which is less? 1 or 2?

    “1”

    “Are you sure? Can you prove it? How do you know?”

    With classes, you know because you’ve told it to be so and you do that by implementing the CompareTo method in the IComparable interface. That’s how you know you: Your class; your instructions!

    Think about something here: When the class is asked to look at this instance and compare it to that instance and make an assessment about which one comes first, what CompareTo is really telling it is to yield a result of 1, 0, or -1:

     

    Value

    Meaning

    Less than zero

    This instance precedes obj in the sort order.

    Zero

    This instance occurs in the same position in the sort order as obj.

    Greater than zero

    This instance follows obj in the sort order.

     

    The result now tells it that it’s less than, equal to, or greater than the other instance. That’s a simple notion but one that seem to befuddle us at first. ;-)

    Using the IComparable interface, you can sort the class easily (and quite quickly too) but it’s pretty rigid isn’t it? What if you want it this way sometimes or that way some other times?

    That’s where LINQ (like I showed in the second example) or using lambda expressions (like IR showed last night) can come in very handy. They take a while to get a good handle on but it’s worth the learning experience.

    Also, like I mentioned last night, a DataTable coupled with a BindingSource is yet another way. The BindingSource has a “Sort” property that’s pretty straightforward.

    With dotNET and most other well-developed programming languages, there are many ways to accomplish anything.

     

    *****

     

    The answer to your question, if it’s not been answered here by someone (me included) already is in yourself.

    Get through some of those articles, try them out and if you get stuck then let’s start again.

    :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Marked as answer by Head_one Wednesday, October 11, 2017 6:38 PM
    Wednesday, October 11, 2017 4:49 PM
  • And to add a simple thing from what Frank wrote related what you reported. Access modifiers likewise Private and Public have nothing to do with it. 

    https://docs.microsoft.com/en-us/dotnet/visual-basic/programming-guide/language-features/declared-elements/access-levels


    Success
    Cor


    • Edited by Cor Ligthert Wednesday, October 11, 2017 5:22 PM
    Wednesday, October 11, 2017 5:22 PM
  • Hello Frank,
       Thank you for writing me a  dotNET mini Manual.
      I read  and have some knowledge about Value types and reference types.
      It is good you added some links, to learn from. I will do it soon.

      Earlier ,IronRazers replied me, and attached a code with a small bug.
      The code works, no run time error, but nothing happens.
      I think he forgot to close a class with "End class". This I will do next.

    I am sure, I can learn from his code.

     
      Next to it, I will read the links you sent.

      Again, thanks for you long explanation. It will help for sure.

        Best regards.

            Moshe.

               

    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 6:26 PM
  • Hello Frank,
       Thank you for writing me a  dotNET mini Manual.
      I read  and have some knowledge about Value types and reference types.
      It is good you added some links, to learn from. I will do it soon.

      Earlier ,IronRazers replied me, and attached a code with a small bug.
      The code works, no run time error, but nothing happens.
      I think he forgot to close a class with "End class". This I will do next.

    I am sure, I can learn from his code.

     
      Next to it, I will read the links you sent.

      Again, thanks for you long explanation. It will help for sure.

        Best regards.

            Moshe.

               

    All things are difficult before they are easy. (unknown)


    You're welcome. :)

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Marked as answer by Head_one Wednesday, October 11, 2017 6:38 PM
    Wednesday, October 11, 2017 6:29 PM
  • Thanks for the link.

         Moshe.


    All things are difficult before they are easy. (unknown)

    Wednesday, October 11, 2017 6:29 PM
  • Ray,

    Why are you showing code which is in fact wrong to use. 

    He uses a struct in his code, which has more change on memory overflow then when were used classes. 

    I've seen many persons here who asked for help. But never gave code from which I knew it was basically wrong because an asker was to lazy to learn the benefit of classes above structures, it takes less time, than the time you've spend to make the code. 

    After a while the same person tells he got a memory overflow in his program which he made with code which he got from IronRazerz and by that giving for others the impression you did not know that.

     


    Success
    Cor

     My point was not about using a Class or Structure,  my main point was about creating and using an Enumeration to pass to a single sorting sub/function.  That is what Head_one was asking about.  He asked...

     "My question: Can I do it with ONE sort subroutine, by sending a parameter that will imply which type of sort to do? Or another way?"

     I do not disagree,  it would be better to use a Class instead of a Structure whenever you can.  I am positive that if someone was to ever look back through my posts from over the years,  they would find where i have recommended the use of a Class instead of a Structure but,  they would never find me recommending the reverse.


    If you say it can`t be done then i`ll try it

    • Marked as answer by Head_one Wednesday, October 11, 2017 6:38 PM
    Wednesday, October 11, 2017 6:34 PM