简体   繁体   English

使用字符串和整数对数组进行数字排序

[英]Sort array numerically, with strings and integers

i have an array which has a name and a score next to it, i need it to be sorted high to low. 我有一个数组,数组旁边有一个名称和一个分数,我需要将其从高到低排序。 i already have it sorted alphabetically. 我已经按字母顺序对其进行了排序。

Dim reply3 As String
Dim name As String
Dim score As Integer = 0
Dim classnum As Integer
Dim filePath As String
Dim reply As Integer
Dim reply2 As Integer
Dim strline As String
Dim array() As String

Sub Main()

    Console.Title = "Math Test"
    Console.WriteLine("Do you want to start the test or view previous results? Press 1 for test, 2 for results")

    reply = Console.ReadLine

    If reply > 2 Then
        MsgBox("Invalid Reply Press Ok to end")
        End
    End If

    If reply = 2 Then
        Console.WriteLine("What class do you want to see the results of? 1, 2, or 3?")
        reply2 = Console.ReadLine()
    End If

    If reply2 > 3 Then
        MsgBox("Invalid Reply Press Ok to exit")
        End
    End If

    Select Case reply2
        Case 1

            Dim results1 As String = File.ReadAllText("Z:\scores class 1.txt")

            array = Split(results1, "-")

            For i As Integer = 0 To array.Length - 1
                Console.WriteLine(array(i))
            Next

            Console.WriteLine("Would you like these to be sorted? Press 1 for yes, 2 for no")
            If Console.ReadLine = 1 Then

                System.Array.Sort(array)

                For i As Integer = 0 To array.Length - 1
                    Console.WriteLine(array(i))
                Next


            ElseIf Console.ReadLine = 2 Then
                End
            End If

            Console.ReadLine()

        Case 2

            Dim results1 As String = File.ReadAllText("Z:\scores class 2.txt")

            array = Split(results1, "-")

            For i As Integer = 0 To array.Length - 1
                Console.WriteLine(array(i))
            Next

            Console.WriteLine("Would you like these to be sorted? Press 1 for yes, 2 for no")
            If Console.ReadLine = 1 Then

                System.Array.Sort(array)

                For i As Integer = 0 To array.Length - 1
                    Console.WriteLine(array(i))
                Next

            ElseIf Console.ReadLine = 2 Then
                End
            End If
            Console.ReadLine()

        Case 3

            Dim results1 As String = File.ReadAllText("Z:\scores class 3.txt")

            array = Split(results1, "-")

            For i As Integer = 0 To array.Length - 1
                Console.WriteLine(array(i))
            Next

            Console.WriteLine("Would you like these to be sorted? Press 1 for yes, 2 for no")
            If Console.ReadLine = 1 Then

                System.Array.Sort(array)

                For i As Integer = 0 To array.Length - 1
                    Console.WriteLine(array(i))
                Next

            ElseIf Console.ReadLine = 2 Then
                End
            End If
            Console.ReadLine()

    End Select

    If reply = 1 Then

        Console.WriteLine("What is your name?")
        name = Console.ReadLine

        Console.WriteLine("What class are you in, 1, 2 or 3?")
        classnum = Console.ReadLine

        If classnum < 1 Then
            MsgBox("Invalid Class number")
            End
        ElseIf classnum > 3 Then
            MsgBox("Invalid Class number")
            End
        End If

        Console.WriteLine("What is 9+10 ?")
        If Console.ReadLine = 19 Then
            score += 1
        End If

        Console.WriteLine("What is 5x10 ?")
        If Console.ReadLine = 50 Then
            score += 1
        End If

        Console.WriteLine("What is 122÷2 ?")
        If Console.ReadLine = 61 Then
            score += 1
        End If

        Console.WriteLine("What is 424 + 10 ?")
        If Console.ReadLine = 434 Then
            score += 1
        End If

        Console.WriteLine("What is 234 x 3 ?")
        If Console.ReadLine = 702 Then
            score += 1
        End If

        Console.WriteLine("What is 10 x 10 ?")
        If Console.ReadLine = 100 Then
            score += 1
        End If

        Console.WriteLine("What is 12 x 64 ?")
        If Console.ReadLine = 768 Then
            score += 1
        End If

        Console.WriteLine("What is the value of N in this equation? 2n+6=10?")
        If Console.ReadLine = 4 Then
            score += 1
        End If

        Console.WriteLine("What is 9 x 73 ?")
        If Console.ReadLine = 657 Then
            score += 1
        End If

        Console.WriteLine("What is 1 + 1 ?")
        If Console.ReadLine = 2 Then
            score += 1

        End If

        MsgBox("Your score was " & score & " Click ok to finish.")

        Dim output1 As String = name & " " & score & "-"

        Select Case classnum
            Case 1
                filePath = System.IO.Path.Combine(
           My.Computer.FileSystem.SpecialDirectories.MyDocuments, "scores class 1.txt")
                My.Computer.FileSystem.WriteAllText(filePath, output1, True)
            Case 2
                filePath = System.IO.Path.Combine(
            My.Computer.FileSystem.SpecialDirectories.MyDocuments, "scores class 2.txt")
                My.Computer.FileSystem.WriteAllText(filePath, output1, True)
            Case 3
                filePath = System.IO.Path.Combine(
            My.Computer.FileSystem.SpecialDirectories.MyDocuments, "scores class 3.txt")
                My.Computer.FileSystem.WriteAllText(filePath, output1, True)
        End Select

    End If

End Sub

I need the array called array to be sorted numerically. 我需要称为数组的数组进行数字排序。 i will add the option for the user to choose if he/she wants further sorting after it has been done alphabetically. 我将为用户添加选项,以便用户按字母顺序选择是否要进一步排序。

Strings are not numbers. 字符串不是数字。 They are text. 它们是文本。

In string format, they are simply characters ( numerals ) and they do not and will not sort numerically: 在字符串格式中,它们只是字符( 数字 ),它们不是也不 将按数字排序:

Dim myVals As String() = {"5", "07", "178", "9", "899", "42", "3"}
' add two of the "numbers"
Console.WriteLine("{0} + {1} = {2}", myVals(0), 
                         myVals(1), (myVals(0) + myVals(1)))
Array.Sort(myVals)
Array.Reverse(myVals)

For Each s As String In myVals
    Console.Write("{0}  ", s)
Next

Output: 输出:

5 + 07 = 507 5 + 07 = 507
9 899 5 42 3 178 07 9 899 5 42 3 178 07

The values do not add as expected, because they are not numbers. 值未按预期添加,因为它们不是数字。 Instead, the code simply concatenates (glues together) two bits of string. 取而代之的是,代码仅将字符串的两位连接在一起(粘合在一起)。 The array contents sort as characters also. 数组内容也按字符排序。 When sorting, "9" will always be seen as larger than the others. 排序时, "9"将始终被视为大于其他值。

This applies to dates stored as strings as well. 这也适用于以字符串形式存储的日期。 "9/16/1914" will always evaluate larger/later than "12/1/2015". “ 9/16/1914”将始终大于/晚于“ 12/1/2015”。

Why 为什么

Because as text, the lexicographical or alphabetical order used (0,1,2,3,4,5,6,7,8,9). 因为作为文本,所以按字典顺序或字母顺序使用(0,1,2,3,4,5,6,7,8,9)。

Stored as string, numbers loose their numeric value (until converted). 数字以字符串形式存储,失去其数值(直到转换)。 "9" sorts higher than "899" because "9" is higher than "899" . "9"高于种"899" ,因为"9" 高于 "899" The same way that "Able" and "Baker" will sort based on "A" and "B". “ Able”和“ Baker”将基于“ A”和“ B”进行排序的方式相同。 The "07" sorts lowest because of the zed. 由于zed, "07"排序最低。 The numerical value is ignored because they are strings (text). 数值被忽略,因为它们是字符串(文本)。

The same is true for string "dates" - they are not dates and have no date value. 字符串“ dates”也是如此-它们不是日期,也没有日期值。 Your brain interprets them as dates based on the pattern; 您的大脑会根据模式将它们解释为日期。 to the computer, they remain text and "9/16/yyyy" will evaluate larger than "12/1/yyyy" . 在计算机上,它们仍然是文本,并且"9/16/yyyy"计算结果将大于"12/1/yyyy"

Sort array numerically, with strings and integers 使用字符串和整数对数组进行数字排序

We now know that there are no integers in string arrays, just numerals. 现在我们知道字符串数组中没有整数,只有数字。 But also, if you have 2 pieces of data, you need to store them separately if you want to use them individually. 但是,如果您有2个数据,则要单独使用它们,则需要分别存储它们。 A Class is ideal for this: 类是理想的选择:

Public Class Student
    Public Property Name As String
    Public Property Score As Integer

    Public Sub New()
    End Sub

    ' overload
    Public Sub New(n As String, s As Integer)
        Name = n
        Score = s
    End Sub

    Public Overrides Function ToString() As String
        Return String.Format("{0} ({1})", Name, Score)
    End Function
End Class

Notice that the name and score are stored as the correct data type which will allow code to use the Score as a numeric value. 请注意,名称和分数存储为正确的数据类型,这将使​​代码将分数用作数字值。 Unlike using 2 arrays, the name cannot become detached from the score. 与使用2个数组不同,该名称不能与乐谱分离。

Note also that ToString() allows us to display the data however we want. 还请注意, ToString()允许我们根据需要显示数据。 Just because we want to show the name and score together does not mean we must glue that information together. 仅仅因为我们想显示名称和分数并不意味着我们必须将这些信息粘合在一起。 Sample output: 样本输出:

Charlie (89) 查理(89)

A Students Container 学生容器

Give up your arrays (and ArrayLists)! 放弃您的数组(和ArrayList)! It is the 21st Century and we have Typed collections (called Generics ): 这是21世纪,我们有Typed集合(称为Generics ):

Private Students As List(of Student)       ' declaration

Students is a collection which can only store Student objects, which in turn contains 2 pieces of data. Students是一个只能存储Student对象的集合,而Student对象又包含2个数据。 Let's add some: 让我们添加一些:

Students = New List(Of Student)         ' create List instance

Dim stud As New Student                 ' create new student
stud.Name = "Harvey"                    ' set props
stud.Score = 72                         ' 72 is a NUMBER
Students.Add(stud)                      ' add to collection

' fast way, using the overload, no temp student object needed
Students.Add(New Student("Bob", 67))
Students.Add(New Student("Hoover", 82))
Students.Add(New Student("Ziggy", 97))
...
Students.Add(New Student("Zoey", 89))

Note that we do not have to set the size of the List(of Student) - it grows as it needs to. 请注意,我们不必设置List(of Student)的大小-它会根据需要增加。 You can still reference them by element/position: Students(0) is a Student object, and Students(0).Name will be the name of the student in the first slot ("Harvey"). 您仍然可以按元素/位置引用它们: Students(0)Student对象, Students(0).Name将是第一个位置(“ Harvey”)中学生的名称。

Sorting 排序

Students = Students.OrderByDescending(Function(x) x.Score).ToList()

This creates a new collection in the desired order. 这将以所需顺序创建一个新集合。 To sort matching scores by name: 按名称对匹配分数进行排序:

Students = Students.OrderByDescending(Function(x) x.Score).
            ThenBy(Function(q) q.Name).ToList()
' print the contents:
For Each st As Student In Students
    Console.WriteLine(st)
Next

The result after adding several matching scores of 89 : 加上多个匹配分数89后的结果:

Ziggy (97) 齐吉(97)
Charlie (89) 查理(89)
Echo (89) 回声(89)
Tango (89) 探戈(89)
Zoey (89) 佐伊(89)
Hoover (82) 胡佛(82)
Harvey (72) 哈维(72)
Bob (67) 鲍勃(67)

To track multiple class scores (hinted at in the code), you could add an Id (1,2,3) or Code ("101", "201", "303") to the class to qualify which class, series or set each User-Score belongs. 要跟踪多个班级成绩(在代码中的提示),您可以向班级添加一个Id (1,2,3)或Code (“ 101”,“ 201”,“ 303”)以限定哪个班级,系列或设置每个用户分数所属的。 Use an additional .Where() above to get just a subset of the master list. 使用上面的其他.Where()仅获得主列表的一个子集。

Finally, rather than storing score sets to individual files, the entire list in its current state can be serialized and saved in 3 or 4 lines of code. 最后,与其将分数集存储到单个文件中,不如将其当前状态的整个列表序列化并保存为3或4行代码。

tl;dr TL;博士

Strings do not contain numbers, nor Dates . 字符串不包含数字,也不包含Dates They are text. 它们是文本。

Don't store individual data elements as one, if you want to use them individually. 如果要单独使用单个数据元素,请不要将其存储为一个。

What you have is a essentially a multidimensional array containing multiple data types (but in your case, you have concatenated each row into a single string). 实际上,您所拥有的是一个包含多种数据类型的多维数组(但在您的情况下,您已将每一行连接到一个字符串中)。 There isn't a catch-all way to handle this situation, but here are a few methods to consider: 没有一种万能的方法来处理这种情况,但是这里有一些需要考虑的方法:

One multidimensional object array: 一个多维对象数组:

Dim array(,) As Object = {{"Student1", 95},{"Student2", 87}...}

Two parallel, one dimensional arrays: 两个平行的一维数组:

Dim names() As String = {"Student1","Student2"...}
Dim scores() As Integer = {95, 87...}

Create a Class or Struct: 创建一个类或结构:

Public Class Student
    Property name As String
    Property score As Integer
End Class

These are all generally better ways of storing your data, but typically put the burden of sorting your data on you. 这些通常都是更好的存储数据的方法,但通常会给您增加对数据进行排序的负担。 Which leads me to the final option... 这导致我最终选择...

Hack together a workaround: 共同解决一个变通方法:

This is essentially what you've already done- concatenated a string with an integer to allow use of the built-in Sort procedure. 本质上,这就是您已经完成的操作-将字符串与整数连接起来,以允许使用内置的Sort过程。 You can use the same trick to sort by score, but you have to 0-pad your integers if you want them to sort correctly. 您可以使用相同的技巧按分数排序,但是如果希望整数正确排序,则必须将其0填充。 See code below, but you've been warned: these type of solutions are invariably easier to implement in the short term but grow unwieldy and less useful in the long term, often needing to be replace by one of the "better" solutions above. 请参阅下面的代码,但是您已经得到警告:这类解决方案在短期内始终易于实现,但从长远来看却变得笨拙且用处不大,通常需要替换为上面的“更好”的解决方案之一。

Private Sub FlipStrings(ByRef students() As String)
    If students Is Nothing Then Exit Sub
    For i As Integer = 0 To UBound(students)
        Dim parts() As String = Split(students(i))
        If parts Is Nothing OrElse UBound(parts) <> 1 Then Continue For
        If IsNumeric(parts(0)) Then
            students(i) = parts(1) & " " & CInt(parts(0))
        ElseIf IsNumeric(parts(1)) Then
            Do Until len(parts(1)) = 3 'Assuming max score of 100'
                parts(1) = "0" & parts(1)
            Loop
            students(i) = parts(1) & " " & parts(0)
        End If
    Next
End Sub

I wrote this so you can still store and display your array exactly as before. 我写了这个,所以您仍然可以像以前一样存储和显示数组。 Now, to sort by score 现在,按分数排序

FlipStrings(array)
System.Array.Sort(array)
FlipStrings(array)

should give you exactly what you're looking for. 应该给您您想要的东西。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM