none
Sort numeric array and sync another array with it RRS feed

  • Question

  • I have a game I'm designing and I need to create a high score list. I collect the scores and player names from a file and store them into two arrays, one is numeric. I would have just used 1 array to simplify it but could not sort numbers and strings.

    So what I'd like to do is sort the score array as descending and keep the player names array order to match. There are probably a lot of different solutions to this. Regular sorting seems to put a score of 1 before 100, and this isn't what I want. 

    My array names:
    ArrayPlayers
    ArrayScores

    Thanks :)


    Programming is mostly just a hobby for me :)

    Tuesday, December 12, 2017 12:19 AM

Answers

  • Here is a way to place labels on the form, in this case I used one label per player but you could of course tweak it to use two.

    I placed a panel on the form, set the following properties.

    Added the following class to the project.

    Public Class PlayerControls
        Public Property labelBaseName As String
        Public Property ParentControl As Control
        Public Sub New()
    
        End Sub
        Public Sub New(ByVal ParentControl As Control)
            ParentControl = ParentControl
            labelBaseName = "lbl"
        End Sub
        Public Sub Create(ByVal pPlayers As List(Of Player))
    
            Dim Base As Integer = 10
    
            Dim labelList As List(Of Label) = pPlayers.Select(
                Function(p, index)
                    Dim singleLabel As New Label With
                        {
                            .Name = String.Concat(labelBaseName, index + 1),
                            .Text = $"{p.Name} - {p.Score}",
                            .Location = New Point(0, Base),
                            .Parent = Me.ParentControl,
                            .Visible = True
                        }
    
                    ParentControl.Controls.Add(singleLabel)
    
                    Base += 22
    
                    Return singleLabel
    
                End Function).ToList
    
        End Sub
    End Class
    

    Form code

    Public Class Form1
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim ops As New PlayerControls(Me)
            Dim Players As New List(Of Player) From
                {
                    New Player With {.Name = "Karen", .Score = 78},
                    New Player With {.Name = "Bob", .Score = 89},
                    New Player With {.Name = "Bob", .Score = 1},
                    New Player With {.Name = "Mary", .Score = 23},
                    New Player With {.Name = "Joe", .Score = 44},
                    New Player With {.Name = "Zack", .Score = 100},
                    New Player With {.Name = "Adam", .Score = 20}
                }
            Dim SortedPlayersScoreDesc As List(Of Player) =
                Players.OrderByDescending(Function(p) p.Score).ToList
            ops.ParentControl = Panel1
            ops.Create(SortedPlayersScoreDesc)
        End Sub
    End Class
    

    We get

    Now about the source, text file, it would be better to store name and score on one line separate by a comma then use a TextFieldParser to get the data into a Player list. Using TextFieldParser as in the example in the page for TextFieldParser each line is split for you so you can use the elements to populate a Player.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Tuesday, December 12, 2017 1:29 PM
    Moderator

All replies

  • The following is for Framework 3.5+. I used a mock up of players (Name + score).

    Public Class Form1
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim Players As New List(Of Player) From
                {
                    New Player With {.Name = "Karen", .Score = 78},
                    New Player With {.Name = "Bob", .Score = 89},
                    New Player With {.Name = "Mary", .Score = 23}
                }
    
            Dim SortedPlayersScoreAsc As IOrderedEnumerable(Of Player) = Players.OrderBy(Function(p) p.Score)
    
            For Each p As Player In SortedPlayersScoreAsc
                Console.WriteLine($"{p.Name}, {p.Score}")
            Next
    
            Console.WriteLine()
    
            Dim SortedPlayersScoreDesc As IOrderedEnumerable(Of Player) = Players.OrderByDescending(Function(p) p.Score)
            For Each p As Player In SortedPlayersScoreDesc
                Console.WriteLine($"{p.Name}, {p.Score}")
            Next
        End Sub
    End Class
    Public Class Player
        Public Property Name As String
        Public Property Score As Integer
    End Class
    

    Results

    Mary, 23
    Karen, 78
    Bob, 89
    
    Bob, 89
    Karen, 78
    Mary, 23
    

    So when reading from a file you start off with

    Dim Players As New List(Of Player)

    When reading from the file, for each player add via

    Players.Add
    Set properties for the add the same as shown in the above code sample but instead of static/mocked data use data from the file.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Tuesday, December 12, 2017 12:33 AM
    Moderator
  • Programmer,

    I'm not sure what you want really, but do understand that two disparate collections is relying on a very weak bond to hold them together: The common index number.

    Sorting or doing anything like that totally destroys that bond. Use a class for this so that you get the power of encapsulation.

    As an example:

    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
            Dim pList As New List(Of Players)
    
            Players.AddUserScore(pList, "Fred", 15)
            Players.AddUserScore(pList, "Sally", 35)
            Players.AddUserScore(pList, "Fred", 36)
            Players.AddUserScore(pList, "Sally", 55)
    
            Dim highScore As Integer = Players.GetHighScore(pList)
    
            Stop
    
        End Sub
    End Class
    
    
    
    
    
    Public Class Players
        Private _name As String
        Private _score As Integer
    
        Private Sub New(ByVal name As String, _
                        ByVal score As Integer)
    
            ' Do validation here ... not included in this
    
            _name = name.Trim
            _score = score
    
        End Sub
    
        Public Shared Sub _
            AddUserScore(ByVal playerList As List(Of Players), _
                         ByVal name As String, _
                         ByVal score As Integer)
    
            ' Validation!!
    
            If playerList IsNot Nothing Then
                playerList.Add(New Players(name, score))
            End If
    
        End Sub
    
        Public Shared Function _
            GetHighScore(ByVal playerList As List(Of Players)) As Integer
    
            If playerList IsNot Nothing Then
                If playerList.Count > 0 Then
                    Return (From p As Players In playerList Select p.Score).Max
                Else
                    Return Nothing
                End If
            End If
    
        End Function
    
        Public ReadOnly Property Name As String
            Get
                Return _name
            End Get
        End Property
    
        Public ReadOnly Property Score As Integer
            Get
                Return _score
            End Get
        End Property
    End Class
    

    That returns a high score of 55.

    If you want to know who got the high score then consider the fact that there may be more than one person who did so you'll actually be returning a collection of "Name" in the above.


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

    Tuesday, December 12, 2017 12:36 AM
  • Regular sorting seems to put a score of 1 before 100, and this isn't what I want. 

    Show the code you are using to do this.  I would expect that if you are sorting ascending, 1 should come before 100.  Why is this not what you want?

    If you are sorting descending and 1 comes before 100, then perhaps you aren't sorting numbers. For instance, strings of different lengths will not fall into numeric order, whichever way you sort them.

    If you take any of the standard sorting algorithms (such as a bubble sort) and you sort it for ArrayScores, then all you need to do is for everywhere there is a pieces of code that moves (eg, swaps) an element in ArrayScores, do exactly the same move for the corresponding elements in ArrayPlayer.

    Tuesday, December 12, 2017 12:40 AM
  • Hi

    Keeping 2 arrays in sync isn't really the best way to go, and is very prone to difficult coding trying to keep tabs on everything.

    An easier/cleaner approach is to use a datatable for the high scores. It combines all the high score data (names, score other statistics etc) all in one easy to save/restore format. Using such a tsble in conjunction with a DataGridView makes everything stay in sync and, can easily be sorted according to whatever criteria makes a score migrate up/down the table.

    I use exactly that type of structure for one of my projects and the coding for it is reasonably straightforward.

    A snippet of setting up the datatable columns:

            With HighScores
                .Columns.Add("Name", GetType(String))
                .Columns.Add("Date", GetType(DateTime))
                .Columns.Add("Score", GetType(Integer))
                .Columns.Add("Level", GetType(Integer))
                .Columns.Add("Success", GetType(String))
                .Columns.Add("Words", GetType(String))
                .Columns.Add("Last", GetType(String))
                .Columns.Add("Easy", GetType(Boolean))
    


    Regards Les, Livingston, Scotland

    Tuesday, December 12, 2017 12:42 AM
  • Rob (I think you once told me that's your name - if not the sorry about that),

    As an additional thought here, you might also want to add the date that the score was registered.

    Doing that, you can then overload the method that I showed earlier and if you then include the date, the results for the high score are "for that date".

    Food for thought...


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

    Tuesday, December 12, 2017 1:05 AM
  • Thank you. I tried playing around with your code and I'm sure your method will work, but I need to use a do...loop. 

    I have this code in my Do....Loop

                Dim Players As New List(Of Player) From
                {
                    New Player With {.Name = PlayerNameTrimmed, .Score = PlayerScore}
                }
    

    I added this line outside of the loop

            Dim SortedPlayersScoreAsc As IOrderedEnumerable(Of Player) = Players.OrderBy(Function(p) p.Score)
    

    And have not yet modified this line:

            For Each p As Player In SortedPlayersScoreAsc
                Console.WriteLine($"{p.Name}, {p.Score}")
            Next
    

    Players in bold gives an error because it is outside of the loop. I need to declare it prior to the loop but do not know how. 



    Programming is mostly just a hobby for me :)

    Tuesday, December 12, 2017 1:18 AM
  • Programmer,

    I don't know who you're talking to and I'm taking off for the night, but you can't keep two arrays together if you then sort one of them (thus changing the index numbers).

    A class, a structure or even a datatable all use encapsulation - if you're not familiar with it then let's talk more tomorrow about it.

    You'll see that it's a marked improvement. :)


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

    Tuesday, December 12, 2017 1:24 AM
  • So what I'd like to do is sort the score array as descending and keep the player names array order to match. There are probably a lot of different solutions to this. Regular sorting seems to put a score of 1 before 100, and this isn't what I want. 

    My array names:
    ArrayPlayers
    ArrayScores

    Thanks :)


    Programming is mostly just a hobby for me :)

    Hi programmer4life,

    You said that you use two array to store player names and scores before, but now you want to simplify it. What you would like to do is sort the score array as descending and keep the player names array order to match.

    I think you can use Dictionary(of string,integer) to do this, for example,

      Dim dic As New Dictionary(Of String, Integer)
            dic.Add("A", 12)
            dic.Add("B", 90)
            dic.Add("D", 45)
            dic.Add("G", 78)
            dic.Add("F", 65)
            dic.Add("H", 56)
            dic.Add("E", 29)
            dic = dic.OrderBy(Function(x) x.Value).ToDictionary(Function(x) x.Key, Function(x) x.Value)
    
            For Each pairvalue As KeyValuePair(Of String, Integer) In dic
                Console.WriteLine("The playername is {0}, score is {1}", pairvalue.Key, pairvalue.Value)
            Next

    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.

    Tuesday, December 12, 2017 6:09 AM
    Moderator
  • This is in response to Karen Payne's reply. Her method seems to be what I will need. It was late for me too and I called it a night, but am determined to get this finished this morning. 

    I have chosen to store score data in an unusual way, so I'm going to explain everything, and no doubt someone will know an easier way to do what I did. I always prefer the least lines of code to keep it easy to read. I only have 1 final question: How to create 20 labels as an array?

    First of all, here it me stored test data for the scores list:

    100-TEST
    160-Programmer4Life
    1000-TEST1000
    1-TEST1

    My goal is to have TEST1000 listed in H_Name1 and the score in L_Score1

    I obviously want TEST1 to be in 4th place in  H_Name4 and the score in L_Score4

    Here is the code I have so far. You will see that I am attempting to access the labels as if they were arrays, but that's the only error now.

    ReadString = "collect from server" FilesTextLines = ReadString.Split(Environment.NewLine.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries) I = 0 Dim Players As New List(Of Player) Do Until I = FilesTextLines.Count DashLoc = FilesTextLines(I).IndexOf("-") PlayerScore = FilesTextLines(I).Substring(0, DashLoc) PlayerNameLen = FilesTextLines(I).Length - (DashLoc + 1) PlayerNameTrimmed = FilesTextLines(I).Substring(DashLoc + 1, (FilesTextLines(I).Length - DashLoc) - 1) Players = New List(Of Player) From { New Player With {.Name = PlayerNameTrimmed, .Score = PlayerScore} } I += 1 Loop Dim SortedPlayersScoreAsc As IOrderedEnumerable(Of Player) = Players.OrderBy(Function(p) p.Score)

    Edit:  

          I = 1
            For Each p As Player In SortedPlayersScoreAsc
                H_Name(I).Text = $"{p.Name}"
                L_Score(I).Text = $"{p.Score}"
                I += 1
            Next

    All of your replies were appreciated, but I went with the first one. I've never used an array like that and think it will work perfectly. 


    Programming is mostly just a hobby for me :)


    • Edited by programmer4life Tuesday, December 12, 2017 12:01 PM Forgot to add the .Text to the labels.
    Tuesday, December 12, 2017 11:57 AM
  • I modified that final part, but it is only showing 1 score which is also the smallest.

            I = 1
            For Each p As Player In SortedPlayersScoreAsc
                If I = 1 Then
                    H_Name1.Text = $"{p.Name}"
                    L_Score1.Text = $"{p.Score}"
                End If
                If I = 2 Then
                    H_Name2.Text = $"{p.Name}"
                    L_Score2.Text = $"{p.Score}"
                End If
                If I = 3 Then
                    H_Name3.Text = $"{p.Name}"
                    L_Score3.Text = $"{p.Score}"
                End If
                If I = 4 Then
                    H_Name4.Text = $"{p.Name}"
                    L_Score4.Text = $"{p.Score}"
                End If
                If I = 5 Then
                    H_Name5.Text = $"{p.Name}"
                    L_Score5.Text = $"{p.Score}"
                End If
                If I = 6 Then
                    H_Name6.Text = $"{p.Name}"
                    L_Score6.Text = $"{p.Score}"
                End If
                If I = 7 Then
                    H_Name7.Text = $"{p.Name}"
                    L_Score7.Text = $"{p.Score}"
                End If
                If I = 8 Then
                    H_Name8.Text = $"{p.Name}"
                    L_Score8.Text = $"{p.Score}"
                End If
                If I = 9 Then
                    H_Name9.Text = $"{p.Name}"
                    L_Score9.Text = $"{p.Score}"
                End If
                If I = 10 Then
                    H_Name10.Text = $"{p.Name}"
                    L_Score10.Text = $"{p.Score}"
                End If
                If I = 11 Then
                    H_Name11.Text = $"{p.Name}"
                    L_Score11.Text = $"{p.Score}"
                End If
                If I = 12 Then
                    H_Name12.Text = $"{p.Name}"
                    L_Score12.Text = $"{p.Score}"
                End If
                If I = 13 Then
                    H_Name13.Text = $"{p.Name}"
                    L_Score13.Text = $"{p.Score}"
                End If
                If I = 14 Then
                    H_Name14.Text = $"{p.Name}"
                    L_Score14.Text = $"{p.Score}"
                End If
                If I = 15 Then
                    H_Name15.Text = $"{p.Name}"
                    L_Score15.Text = $"{p.Score}"
                End If
                If I = 16 Then
                    H_Name16.Text = $"{p.Name}"
                    L_Score16.Text = $"{p.Score}"
                End If
                If I = 17 Then
                    H_Name17.Text = $"{p.Name}"
                    L_Score17.Text = $"{p.Score}"
                End If
                If I = 18 Then
                    H_Name18.Text = $"{p.Name}"
                    L_Score18.Text = $"{p.Score}"
                End If
                If I = 19 Then
                    H_Name19.Text = $"{p.Name}"
                    L_Score19.Text = $"{p.Score}"
                End If
                If I = 20 Then
                    H_Name20.Text = $"{p.Name}"
                    L_Score20.Text = $"{p.Score}"
                End If
    
                I += 1
            Next
    
    I'm sure there is a simpler way of doing this. TEST1's score of 1 is the only one displayed and it at the top of the list. I will keep trying to determine what the issue is. If any of you have a suggestion, I'm all eyes :)


    Programming is mostly just a hobby for me :)

    Tuesday, December 12, 2017 12:49 PM
  • I'm sure I'm close to having this working but am getting an object reference not set error.

    Here is my code now:

            ReadString = "collect file data"
            FilesTextLines = ReadString.Split(Environment.NewLine.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries)
    
            I = 0
            Do Until I = FilesTextLines.Count
                DashLoc = FilesTextLines(I).IndexOf("-")
                PlayerScore(I) = FilesTextLines(I).Substring(0, DashLoc)
                PlayerNameLen = FilesTextLines(I).Length - (DashLoc + 1)
                PlayerNameTrimmed(I) = FilesTextLines(I).Substring(DashLoc + 1, (FilesTextLines(I).Length - DashLoc) - 1)
                I += 1
            Loop
    
            I = 0
            Dim Players As New List(Of Player)
            Do Until I = PlayerNameTrimmed.Count
                Players = New List(Of Player) From
                 {
                        New Player With {.Name = PlayerNameTrimmed(I), .Score = PlayerScore(I)}
                 }
                I += 1
            Loop
            Dim SortedPlayersScoreAsc As IOrderedEnumerable(Of Player) = Players.OrderBy(Function(p) p.Score)
    
            I = 1
            For Each p As Player In SortedPlayersScoreAsc
                If I = 1 Then
                    H_Name1.Text = $"{p.Name}"
                    L_Score1.Text = $"{p.Score}"
                End If
                If I = 2 Then
                    H_Name2.Text = $"{p.Name}"
                    L_Score2.Text = $"{p.Score}"
                End If
                If I = 3 Then
                    H_Name3.Text = $"{p.Name}"
                    L_Score3.Text = $"{p.Score}"
                End If
                If I = 4 Then
                    H_Name4.Text = $"{p.Name}"
                    L_Score4.Text = $"{p.Score}"
                End If
                If I = 5 Then
                    H_Name5.Text = $"{p.Name}"
                    L_Score5.Text = $"{p.Score}"
                End If
                If I = 6 Then
                    H_Name6.Text = $"{p.Name}"
                    L_Score6.Text = $"{p.Score}"
                End If
                If I = 7 Then
                    H_Name7.Text = $"{p.Name}"
                    L_Score7.Text = $"{p.Score}"
                End If
                If I = 8 Then
                    H_Name8.Text = $"{p.Name}"
                    L_Score8.Text = $"{p.Score}"
                End If
                If I = 9 Then
                    H_Name9.Text = $"{p.Name}"
                    L_Score9.Text = $"{p.Score}"
                End If
                If I = 10 Then
                    H_Name10.Text = $"{p.Name}"
                    L_Score10.Text = $"{p.Score}"
                End If
                If I = 11 Then
                    H_Name11.Text = $"{p.Name}"
                    L_Score11.Text = $"{p.Score}"
                End If
                If I = 12 Then
                    H_Name12.Text = $"{p.Name}"
                    L_Score12.Text = $"{p.Score}"
                End If
                If I = 13 Then
                    H_Name13.Text = $"{p.Name}"
                    L_Score13.Text = $"{p.Score}"
                End If
                If I = 14 Then
                    H_Name14.Text = $"{p.Name}"
                    L_Score14.Text = $"{p.Score}"
                End If
                If I = 15 Then
                    H_Name15.Text = $"{p.Name}"
                    L_Score15.Text = $"{p.Score}"
                End If
                If I = 16 Then
                    H_Name16.Text = $"{p.Name}"
                    L_Score16.Text = $"{p.Score}"
                End If
                If I = 17 Then
                    H_Name17.Text = $"{p.Name}"
                    L_Score17.Text = $"{p.Score}"
                End If
                If I = 18 Then
                    H_Name18.Text = $"{p.Name}"
                    L_Score18.Text = $"{p.Score}"
                End If
                If I = 19 Then
                    H_Name19.Text = $"{p.Name}"
                    L_Score19.Text = $"{p.Score}"
                End If
                If I = 20 Then
                    H_Name20.Text = $"{p.Name}"
                    L_Score20.Text = $"{p.Score}"
                End If
    
                I += 1
            Next
    


    Programming is mostly just a hobby for me :)

    Tuesday, December 12, 2017 1:17 PM
  • This is in response to Karen Payne's reply. Her method seems to be what I will need.

    Make sure that you fully understand it. If you don't then you'll get tripped up later on when you modify it.

    I'm glad that you've found your answer. :)


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

    Tuesday, December 12, 2017 1:21 PM
  • Here is a way to place labels on the form, in this case I used one label per player but you could of course tweak it to use two.

    I placed a panel on the form, set the following properties.

    Added the following class to the project.

    Public Class PlayerControls
        Public Property labelBaseName As String
        Public Property ParentControl As Control
        Public Sub New()
    
        End Sub
        Public Sub New(ByVal ParentControl As Control)
            ParentControl = ParentControl
            labelBaseName = "lbl"
        End Sub
        Public Sub Create(ByVal pPlayers As List(Of Player))
    
            Dim Base As Integer = 10
    
            Dim labelList As List(Of Label) = pPlayers.Select(
                Function(p, index)
                    Dim singleLabel As New Label With
                        {
                            .Name = String.Concat(labelBaseName, index + 1),
                            .Text = $"{p.Name} - {p.Score}",
                            .Location = New Point(0, Base),
                            .Parent = Me.ParentControl,
                            .Visible = True
                        }
    
                    ParentControl.Controls.Add(singleLabel)
    
                    Base += 22
    
                    Return singleLabel
    
                End Function).ToList
    
        End Sub
    End Class
    

    Form code

    Public Class Form1
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            Dim ops As New PlayerControls(Me)
            Dim Players As New List(Of Player) From
                {
                    New Player With {.Name = "Karen", .Score = 78},
                    New Player With {.Name = "Bob", .Score = 89},
                    New Player With {.Name = "Bob", .Score = 1},
                    New Player With {.Name = "Mary", .Score = 23},
                    New Player With {.Name = "Joe", .Score = 44},
                    New Player With {.Name = "Zack", .Score = 100},
                    New Player With {.Name = "Adam", .Score = 20}
                }
            Dim SortedPlayersScoreDesc As List(Of Player) =
                Players.OrderByDescending(Function(p) p.Score).ToList
            ops.ParentControl = Panel1
            ops.Create(SortedPlayersScoreDesc)
        End Sub
    End Class
    

    We get

    Now about the source, text file, it would be better to store name and score on one line separate by a comma then use a TextFieldParser to get the data into a Player list. Using TextFieldParser as in the example in the page for TextFieldParser each line is split for you so you can use the elements to populate a Player.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Tuesday, December 12, 2017 1:29 PM
    Moderator
  • Thank you. I tried playing around with your code and I'm sure your method will work, but I need to use a do...loop. 

    I have this code in my Do....Loop

                Dim Players As New List(Of Player) From
                {
                    New Player With {.Name = PlayerNameTrimmed, .Score = PlayerScore}
                }

    I added this line outside of the loop

            Dim SortedPlayersScoreAsc As IOrderedEnumerable(Of Player) = Players.OrderBy(Function(p) p.Score)

    And have not yet modified this line:

            For Each p As Player In SortedPlayersScoreAsc
                Console.WriteLine($"{p.Name}, {p.Score}")
            Next

    Players in bold gives an error because it is outside of the loop. I need to declare it prior to the loop but do not know how. 



    Programming is mostly just a hobby for me :)

    Here is a working project to work with

    https://1drv.ms/u/s!AtGAgKKpqdWjiQQA8J1DpEgPR24I


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Tuesday, December 12, 2017 1:33 PM
    Moderator
  • Thanks Karen. I've solved this with your help :) I noticed that the scores were being listed exactly opposite, with 20th place being the high scores, so I simply flipped the numbers. 

    My working code:

            Dim Players As New List(Of Player)
            Players = New List(Of Player) From
             {
                 New Player With {.Name = PlayerNameTrimmed(0), .Score = PlayerScore(0)},
                 New Player With {.Name = PlayerNameTrimmed(1), .Score = PlayerScore(1)},
                 New Player With {.Name = PlayerNameTrimmed(2), .Score = PlayerScore(2)},
                 New Player With {.Name = PlayerNameTrimmed(3), .Score = PlayerScore(3)},
                 New Player With {.Name = PlayerNameTrimmed(4), .Score = PlayerScore(4)},
                 New Player With {.Name = PlayerNameTrimmed(5), .Score = PlayerScore(5)},
                 New Player With {.Name = PlayerNameTrimmed(6), .Score = PlayerScore(6)},
                 New Player With {.Name = PlayerNameTrimmed(7), .Score = PlayerScore(7)},
                 New Player With {.Name = PlayerNameTrimmed(8), .Score = PlayerScore(8)},
                 New Player With {.Name = PlayerNameTrimmed(9), .Score = PlayerScore(9)},
                 New Player With {.Name = PlayerNameTrimmed(10), .Score = PlayerScore(10)},
                 New Player With {.Name = PlayerNameTrimmed(11), .Score = PlayerScore(11)},
                 New Player With {.Name = PlayerNameTrimmed(12), .Score = PlayerScore(12)},
                 New Player With {.Name = PlayerNameTrimmed(13), .Score = PlayerScore(13)},
                 New Player With {.Name = PlayerNameTrimmed(14), .Score = PlayerScore(14)},
                 New Player With {.Name = PlayerNameTrimmed(15), .Score = PlayerScore(15)},
                 New Player With {.Name = PlayerNameTrimmed(16), .Score = PlayerScore(16)},
                 New Player With {.Name = PlayerNameTrimmed(17), .Score = PlayerScore(17)},
                 New Player With {.Name = PlayerNameTrimmed(18), .Score = PlayerScore(18)},
                 New Player With {.Name = PlayerNameTrimmed(19), .Score = PlayerScore(19)}
             }
            Dim SortedPlayersScoreAsc As IOrderedEnumerable(Of Player) = Players.OrderBy(Function(p) p.Score())
    
            I = 1
            For Each p As Player In SortedPlayersScoreAsc
                If I = 1 Then
                    H_Name20.Text = $"{p.Name}"
                    L_Score20.Text = $"{p.Score}"
                End If
                If I = 2 Then
                    H_Name19.Text = $"{p.Name}"
                    L_Score19.Text = $"{p.Score}"
                End If
                If I = 3 Then
                    H_Name18.Text = $"{p.Name}"
                    L_Score18.Text = $"{p.Score}"
                End If
                If I = 4 Then
                    H_Name17.Text = $"{p.Name}"
                    L_Score17.Text = $"{p.Score}"
                End If
                If I = 5 Then
                    H_Name16.Text = $"{p.Name}"
                    L_Score16.Text = $"{p.Score}"
                End If
                If I = 6 Then
                    H_Name15.Text = $"{p.Name}"
                    L_Score15.Text = $"{p.Score}"
                End If
                If I = 7 Then
                    H_Name14.Text = $"{p.Name}"
                    L_Score14.Text = $"{p.Score}"
                End If
                If I = 8 Then
                    H_Name13.Text = $"{p.Name}"
                    L_Score13.Text = $"{p.Score}"
                End If
                If I = 9 Then
                    H_Name12.Text = $"{p.Name}"
                    L_Score12.Text = $"{p.Score}"
                End If
                If I = 10 Then
                    H_Name11.Text = $"{p.Name}"
                    L_Score11.Text = $"{p.Score}"
                End If
                If I = 11 Then
                    H_Name10.Text = $"{p.Name}"
                    L_Score10.Text = $"{p.Score}"
                End If
                If I = 12 Then
                    H_Name9.Text = $"{p.Name}"
                    L_Score9.Text = $"{p.Score}"
                End If
                If I = 13 Then
                    H_Name8.Text = $"{p.Name}"
                    L_Score8.Text = $"{p.Score}"
                End If
                If I = 14 Then
                    H_Name7.Text = $"{p.Name}"
                    L_Score7.Text = $"{p.Score}"
                End If
                If I = 15 Then
                    H_Name6.Text = $"{p.Name}"
                    L_Score6.Text = $"{p.Score}"
                End If
                If I = 16 Then
                    H_Name5.Text = $"{p.Name}"
                    L_Score5.Text = $"{p.Score}"
                End If
                If I = 17 Then
                    H_Name4.Text = $"{p.Name}"
                    L_Score4.Text = $"{p.Score}"
                End If
                If I = 18 Then
                    H_Name3.Text = $"{p.Name}"
                    L_Score3.Text = $"{p.Score}"
                End If
                If I = 19 Then
                    H_Name2.Text = $"{p.Name}"
                    L_Score2.Text = $"{p.Score}"
                End If
                If I = 20 Then
                    H_Name1.Text = $"{p.Name}"
                    L_Score1.Text = $"{p.Score}"
                End If
    
                I += 1
            Next
    
    :)

    Programming is mostly just a hobby for me :)

    Tuesday, December 12, 2017 2:12 PM
  • programmer,

    I'm going to add this here for the sake of others. I've often found that they don't fully understand the power of encapsulation and providing it is quite easily done with VB net.

    For my examples, let's say that we need to associate first names with last names. If you use two arrays (or lists, or any other collection) you might envision it like this:

    That works pretty well, right? The index keeps first names and last names together after all.

    The common index is a very weak link though and doing something seemingly minor will eviscerate the connection. Let's say, for instance, that we want to sort those based on the first name:

    Uhh, that didn't work out so well I think you'll agree. ;-)

    Is there a better way? Yes - using encapsulation:

    That's not some high-minded theory -- it's a natural part of OOP and it's easy to do. By creating an object and that object has "attributes" of first name and last name, you're always dealing with one single entity: That one object.

    So how easy is it? I'm not a fan of auto-implemented properties but that's not to say that they won't work. We need to create a class which has these two attributes (properties here) of first name and last name:

    Public Class Person
        Public Property FirstName As String
        Public Property LastName As String
    
        Public Overrides Function ToString() As String
            Return String.Format("{0} {1}", FirstName, LastName)
        End Function
    End Class

    The overridden "ToString" is just so I can show you in the following. I'll first add those names and then next I'll have a look at the list where I stored them:

    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
            Dim pList As New List(Of Person)
    
            With pList
                .Add(New Person With {.FirstName = "George", .LastName = "Washington"})
                .Add(New Person With {.FirstName = "Thomas", .LastName = "Jefferson"})
                .Add(New Person With {.FirstName = "John", .LastName = "Adams"})
                .Add(New Person With {.FirstName = "Benjamin", .LastName = "Franklin"})
                .Add(New Person With {.FirstName = "James", .LastName = "Madison"})
            End With
    
            Stop
    
            Dim sorted As System.Linq.IOrderedEnumerable(Of Person) = _
                From p As Person In pList _
                    Order By p.FirstName
    
            Stop
    
    
        End Sub
    End Class

    The first "Stop" lets me look at the list to see what's in there (stored in natural order):

    I let the code continue and at the second "Stop", I then have a look at the sorted collection:

    First name and last name stay together no matter what; it's all one single object and that's a very powerful notion.

    :)


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

    Tuesday, December 12, 2017 3:09 PM