在计算最小值和最大值时,从String转换为Double类型无效

时间:2017-03-16 10:59:06

标签: vb.net

我的代码收到以下错误:

  

从String转换为Double类型无效

程序在输出正确之前正常运行但是我做了一些无效的更改并且必须还原它们,但它没有工作。

该程序用于在文本文件的列中查找minmax值。

如果可能,请建议一种计算文本文件中多个列的minmax值的方法,这些值用空格(不一致的空格)分隔,其方法与下面的代码有些相似。

Dim Textfile As String
Dim openDlg As New OpenFileDialog

If openDlg.ShowDialog() = DialogResult.OK Then
    openDlg.Filter = "txt files (*.txt)| *.txt|All files (*.*)|*.*"
    openDlg.FilterIndex = 2
    openDlg.RestoreDirectory = True
    Textfile = openDlg.FileName


    Dim RECfile As New System.IO.StreamReader(Textfile)
    Dim textline As String

    Dim ln = 0
    Dim Max As Integer
    Max = 0
    Dim Min As Integer
    Min = 999999

    Do While RECfile.Peek() <> -1
        textline = RECfile.ReadLine()

        If textline > Max Then
            Max = textline
        End If

        If textline < Min Then
            Min = textline
        End If

        ln += 1

        Me.maxval.Text = Max
        Me.Minval.Text = Min

    Loop

    RECfile.Close()

End If

样本数据1:

194787.5    194987.5          194787.5  194987.5
194987.5    195012.5          194987.5  195012.5
195012.5    2003999           195012.5  2003999
2003999     195037.5          2003999   195037.5
195037.5    195062.5          195037.5  195062.5
195062.5    195087.5          195062.5  195087.5
195087.5    195112.5          195087.5  195112.5
195112.5    195137.5          195112.5  495137.5
195137.5    195162.5          195137.5  195162.5
195162.5    194812.5          195162.5  19400012.5
        194837.5            194837.5
        194862.5            194862.5
        194887.5            194887.5
        194912.5            194912.5
        194937.5            194937.5
        12111               12111999    

样本日期2:

194987.5    195012.5          194987.5  195012.5
195012.5    2003999           195012.5  2003999
2003999     195037.5          2003999   195037.5
195037.5    195062.5          195037.5  195062.5
195062.5    195087.5          195062.5  195087.5
195087.5    195112.5          195087.5  195112.5
195112.5    195137.5          195112.5  495137.5
195137.5    195162.5          195137.5  195162.5
195162.5    194812.5          195162.5  19400012.5
        194837.5            194837.5
        194862.5            194862.5
        194887.5            194887.5
        194912.5            194912.5
        194937.5            194937.5

编辑:

这些是我收到的警告的屏幕截图,我认为它与代码相关联。

截屏1: enter image description here

截屏2:

designer form

1 个答案:

答案 0 :(得分:2)

根据您的示例数据,Integer不会削减它。我建议您更改为使用Double而不是 194787.5 不会解析为Integer

首先转向 Option Strict On

  

将隐式数据类型转换限制为仅扩展转换,禁止后期绑定,并禁止导致Object类型的隐式类型。

接下来,我建议您创建一个新的临时变量并使用Double.TryParse

  

将数字的字符串表示形式转换为其等效的双精度浮点数。返回值表示转换是成功还是失败。

对您的代码的建议看起来与此类似:

Dim temp As Double = 0

If Double.TryParse(textline, temp) Then

    If temp > Max Then
        Max = temp
    End If

    If temp < Min Then
        Min = temp
    End If

End If

Me.maxval.Text = Max.ToString()
Me.Minval.Text = Min.ToString()

请注意.ToString()Max上的Min。这是因为它们是Doubles,需要转换为String

我想提出的另一个建议是实施Using来帮助处理对象。

而不是:

Dim RECfile As New System.IO.StreamReader(Textfile)

你会:

Using RECfile As New System.IO.StreamReader(Textfile)

   ...

End Using

您无需致电RECfile.Close(),因为Using区块会处理此问题。

我也看不到变量ln的任何使用,所以删除它。

最后,您声明文本文件包含多个以不一致的空格分隔的列。我实际上相信它们是以制表符分隔的值。话虽如此Andrew Morton提出了一个非常好的建议:

  

..拆分{CChar(vbTab),“”c,以防万一值之间没有标签(例如文件是手工编辑的)。

我建议我们使用String.Split方法:

Dim textline As String() = RECfile.ReadLine().Split(New Char() {CChar(vbTab), " "c}, StringSplitOptions.RemoveEmptyEntries)

总体而言,您的代码看起来与此类似:

Using RECfile As New System.IO.StreamReader(Textfile)

    Dim Max As Double = Double.MinValue
    Dim Min As Double = Double.MaxValue

    Do While RECfile.Peek() <> -1
        Dim textline As String() = RECfile.ReadLine().Split(New Char() {CChar(vbTab), " "c}, StringSplitOptions.RemoveEmptyEntries)

        For Each line In textline
            Dim temp As Double = 0

            If Double.TryParse(line.Trim(), temp) Then

                If temp > Max Then
                    Max = temp
                End If

                If temp < Min Then
                    Min = temp
                End If

            End If

            Me.maxval.Text = Max.ToString()
            Me.Minval.Text = Min.ToString()

        Next
    Loop

End Using

我的输出是:

Max = 19400012.5
Min = 12111
  

根据OP的请求编辑,以获取文本文件中每列的最小值和最大值。

我已尽力尝试分析样本数据,并从中可以看出值是以制表符分隔的。如果列中缺少值,则会找到彼此相邻的两个选项卡。如果两个相邻列中存在缺失值,则会找到彼此相邻的四个选项卡。为了解决这个问题,我用一个标签替换了所有出现的两个标签。这使索引保持稳定。

首先,我创建了两个类:

ColumnValue

Public Class ColumnValue
    Public Key As String

    Public Sub New(ByVal id As Integer,
                   ByVal value As Double)

        _id = id
        _value = value

    End Sub

    Private _id As Integer
    Public ReadOnly Property ID As Integer
        Get
            Return _id
        End Get
    End Property

    Private _value As Double
    Public ReadOnly Property Value As Double
        Get
            Return _value
        End Get
    End Property

End Class

ColumnValues

Imports System.Collections.ObjectModel
Public Class ColumnValues
    Inherits KeyedCollection(Of String, ColumnValue)

    Protected Overrides Function GetKeyForItem(ByVal item As ColumnValue) As String
        Return item.Key
    End Function

    Public Function GetMax(ByVal columnId As Integer) As Double

        Return (From c In Me
                Where c.ID = columnId
                Select c.Value).Max()

    End Function

    Public Function GetMin(ByVal columnId As Integer) As Double

        Return (From c In Me
                Where c.ID = columnId
                Select c.Value).Min()

    End Function

End Class

请注意,在ColumnValues课程中,根据使用LINQ传递的Min,我有两个函数可以返回MaxcolumnId

这是我修改后的代码:

Dim myColumnValues As New ColumnValues

Using RECfile As New System.IO.StreamReader(Textfile)

    Do While RECfile.Peek() <> -1
        Dim textline As String() = RECfile.ReadLine().Replace(CChar(vbTab) & CChar(vbTab), vbTab).Split(New Char() {CChar(vbTab)})

        Dim columnId As Integer = 0

        For Each column In textline

            columnId += 1

            Dim temp As Double = 0

            If Double.TryParse(column.Trim(), temp) Then
                myColumnValues.Add(New ColumnValue(columnId, temp))
            End If

        Next
    Loop

    'Get a distinct list of column Ids to loop through
    Dim columnIds = (From c In myColumnValues
                     Order By c.ID
                     Select c.ID).Distinct()

    'Output the Max and Min for each column
    For Each c In columnIds

        Debug.WriteLine("Column: " & c.ToString() & " Max: " & myColumnValues.GetMax(c))
        Debug.WriteLine("Column: " & c.ToString() & " Min: " & myColumnValues.GetMin(c))

    Next

End Using

请注意,我必须恢复分割vbTab而不是分割标签和空格。通过拆分空间也导致了索引的许多问题,而且数据还不够好。

样本数据1 的输出为:

Column: 1 Max: 2003999
Column: 1 Min: 194787.5

Column: 2 Max: 2003999
Column: 2 Min: 12111

Column: 3 Max: 2003999
Column: 3 Min: 194787.5

Column: 4 Max: 19400012.5
Column: 4 Min: 194837.5

样本数据2 的输出为:

Column: 1 Max: 2003999
Column: 1 Min: 194987.5

Column: 2 Max: 2003999
Column: 2 Min: 194812.5

Column: 3 Max: 2003999
Column: 3 Min: 194987.5

Column: 4 Max: 19400012.5
Column: 4 Min: 194837.5

根据OP关于屏幕截图错误的编辑进行编辑。

我会为ClassColumnValue创建单独的ColumnValues文件,如下所示:

ColumnValue

enter image description here

ColumnValues

enter image description here

将这些内容与您的Form1代码分开。