英文:
2-D array from txt in VB.NET
问题
我需要创建一个代码,足够灵活,可以在将来最小程度地重构我的代码来添加更多列。我的当前代码不允许我使用二维数组遍历我的文件。如果我要更改 MsgBox("map = " + map(0,1),我可以轻松地检索值。目前在列出的代码中,我得到的只是 'System.IndexOutOfRangeException',索引超出了数组的界限。我的当前文本文件是15行(向下)和2列(向横),这使其成为一个14x1的数组。它们也是以逗号分隔的值。
Dim map(14, 1) as string
Dim reader As IO.StreamReader
reader = IO.File.OpenText("C:\LocationOfTextFile")
Dim Linie As String, x, y As Integer
For x = 0 To 14
Linie = reader.ReadLine.Trim
For y = 0 To 1
map(x, y) = Split(Linie, ",")(y)
Next 'y
Next 'x
reader.Close()
MsgBox("map = " + map(y, x))
英文:
I am needing to create a code that is versatile enough where I can add more columns in the future with minimum reconstruction of my code. My current code does not allow me to travel through my file with my 2-D array. If I was to change MsgBox("map = "+ map(0,1) I can retrieve the value easily. Currently all I get in the code listed is 'System.IndexOutOfRangeException' and that Index was outside the bounds of the array. My current text file is 15 rows (down) and 2 columns (across) which puts it at a 14x1. they are also comma separated values.
Dim map(14,1) as string
Dim reader As IO.StreamReader
reader = IO.File.OpenText("C:\LocationOfTextFile")
Dim Linie As String, x,y As Integer
For x = 0 To 14
Linie = reader.ReadLine.Trim
For y = 0 To 1
map(x,y) = Split(Linie, ",")(y)
Next 'y
Next 'x
reader.Close()
MsgBox("map = " + map(y,x))``
答案1
得分: 1
这是Microsoft建议的方法。它是通用的,适用于任何格式正确的逗号分隔文件。它还会捕获并显示在文件中发现的任何错误。
使用 MyReader As New Microsoft.VisualBasic.
FileIO.TextFieldParser(
"C:\文本文件的位置")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
MsgBox(currentField)
Next
Catch ex As Microsoft.VisualBasic.
FileIO.MalformedLineException
MsgBox("行 " & ex.Message &
" 不是有效的,将被跳过。")
End Try
End While
End Using
英文:
This is the method suggested by Microsoft. It is generic and will work on any properly formatted comma delimited file. It will also catch and display any errors found in the file.
Using MyReader As New Microsoft.VisualBasic.
FileIO.TextFieldParser(
"C:\LocationOfTextFile")
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
Dim currentField As String
For Each currentField In currentRow
MsgBox(currentField)
Next
Catch ex As Microsoft.VisualBasic.
FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
答案2
得分: 1
这是一个查看文件读取的通用方法:
Dim data As New List(Of List(Of String))
For Each line As String In IO.File.ReadAllLines("C:\文本文件的位置")
data.Add(New List(Of String)(line.Split(",")))
Next
Dim row As Integer = 1
Dim col As Integer = 10
Dim value As String = data(row)(col)
英文:
Here's a generic way to look at reading the file:
Dim data As New List(Of List(Of String))
For Each line As String In IO.File.ReadAllLines("C:\LocationOfTextFile")
data.Add(New List(Of String)(line.Split(",")))
Next
Dim row As Integer = 1
Dim col As Integer = 10
Dim value As String = data(row)(col)
答案3
得分: 0
基本上您在问的是如何将逗号分隔值的内容转换为二维数组。
最简单的方法,不一定是最佳方法,是返回一个 IEnumerable(Of IEnumerable(Of String))
。项目的数量将在垂直方向上基于行数增长,在水平方向上基于逗号分隔的各行数值增长。
大致如下:
Private Function GetMap(path As String) As IEnumerable(Of IEnumerable(Of String))
Dim map = New List(Of IEnumerable(Of String))()
Dim lines = IO.File.ReadAllLines(path)
For Each line In lines
Dim row = New List(Of String)()
Dim values = line.Split(","c)
row.AddRange(values)
map.Add(row)
Next
Return map
End Function
现在,当您想使用 (row, column)
语法获取特定单元格时,可以使用:
Private _map As IEnumerable(Of IEnumerable(Of String))
Private Sub LoadMap()
_map = GetMap("C:/path-to-map")
End Sub
Private Function GetCell(row As Integer, column As Integer) As String
If (_map Is Nothing) Then
LoadMap()
End If
Return _map.ElementAt(row).ElementAt(column)
End Function
这里有一个示例:https://dotnetfiddle.net/ZmY5Ki
请记住,在实现时存在一些问题,例如:
- 如果单元格中有逗号怎么办?
- 如果尝试访问一个不存在的单元格怎么办?
这些是您在更详细实现时需要考虑的问题。
英文:
Essentially what you are asking is how can I take the contents of comma-separated values and convert this to a 2D array.
The easiest way, which is not necessarily the best way, is to return an IEnuemrable(Of IEnumerable(Of String)). The number of items will grow both vertically based on the number of lines and the number of items will grow horizontally based on the values split on a respective line by a comma.
Something along these lines:
Private Function GetMap(path As String) As IEnumerable(Of IEnumerable(Of String)
Dim map = New List(Of IEnumerable(Of String))()
Dim lines = IO.File.ReadAllLines(path)
For Each line In lines
Dim row = New List(Of String)()
Dim values = line.Split(","c)
row.AddRange(values)
map.Add(row)
Next
Return map
End Function
Now when you want to grab a specific cell using the (row, column)
syntax, you could use:
Private _map As IEnumerable(Of IEnumerable(Of String))
Private Sub LoadMap()
_map = GetMap("C:/path-to-map")
End Sub
Private Function GetCell(row As Integer, column As Integer) As String
If (_map Is Nothing) Then
LoadMap()
End If
Return _map.ElementAt(row).ElementAt(column)
End Function
Here is an example: https://dotnetfiddle.net/ZmY5Ki
Keep in mind that there are some issues with this, for example:
- What if you have commas in your cells?
- What if you try to access a cell that doesn't exist?
These are considerations you need to make when implementing this in more detail.
答案4
得分: 0
你可以考虑使用DataTable
类来实现这个。它比数组占用更多的内存,但在添加列、筛选等方面提供了很大的灵活性。你也可以通过名称而不是索引来访问列。
你可以将其绑定到DataGridView
以可视化数据。
这有点像是一个内存中的数据库。
英文:
You can consider the DataTable
class for this. It uses much more memory than an array, but gives you a lot of versatility in adding columns, filtering, etc. You can also access columns by name rather than index.
You can bind to a DataGridView
for visualizing the data.
It is something like an in-memory database.
答案5
得分: 0
这很类似于@Idle_Mind的建议,但通过使用数组而不是列表来保存单独的行,可以节省数组复制操作和至少一次分配每行的操作:
```vb
Dim data = File.ReadLines("C:\LocationOfTextFile").
Select(Function(ln) ln.Split(","c)).
ToList()
' 显示最后一行和最后一列:
Dim lastRow As Integer = data.Count - 1
Dim lastCol As Integer = data(row).Length - 1
MsgBox($"map = {data(lastRow)(lastCol)}")
这里,假设使用了 Option Infer
,data
变量将是一个 List(Of String())
。
作为升级,您还可以定义一个类,其字段对应于预期的 CSV 列,并在调用 .ToList()
之前将数组元素映射到类属性,这是另一个对 .Select()
的调用。
但我 真正 建议的是从 NuGet 获取一个专用的 CSV 解析器。虽然特定的 CSV 源通常是一致的,但更广泛地说,该格式以易于使 Split()
函数混淆的许多边缘情况而闻名。因此,使用专用解析器可以获得更好的性能和一致性,NuGet 上有几个不错的选择。
<details>
<summary>英文:</summary>
This is much like @Idle_Mind's suggestion, but saves an array copy operation and at least one allocation _per row_ by using an array, rather than a list, for the individual rows:
```vb
Dim data = File.ReadLines("C:\LocationOfTextFile").
Select(Function(ln) ln.Split(","c)).
ToList()
' Show last row and column:
Dim lastRow As Integer = data.Count - 1
Dim lastCol As Integer = data(row).Length - 1
MsgBox($"map = {data(lastRow)(lastCol)}")
Here, assuming Option Infer
, the data
variable will be a List(Of String())
As a step up from this, you could also define a class with fields corresponding to the expected CSV columns, and map the array elements to the class properties as another call to .Select()
before calling .ToList()
.
But what I really recommend is getting a dedicated CSV parser from NuGet. While a given CSV source is usually consistent, more broadly the format is known for having a number of edge cases that can easily confound the Split()
function. Therefore you tend to get better performance and consistency from a dedicated parser, and NuGet has several good options.
答案6
得分: 0
这是一个简单的示例,展示了如何使用第一行来决定文件有多少列。我们以(列, 行)
的顺序存储数组,因为Redim Preserve
只对数组的最后一个索引起作用(我们更有可能添加行而不是列)。
Dim filename = "C:\Junk\example.csv"
Dim lines = System.IO.File.ReadAllLines(filename)
If lines.Length > 0 Then
Dim colCount = Split(lines(0), ",").Length
Dim rowCount = lines.Length
Dim map(colCount - 1, rowCount - 1)
For row = 0 To rowCount - 1
Dim values = Split(lines(row), ",", colCount)
For col = 0 To colCount - 1
map(col, row) = values(col)
Next col
Next row
'显示结果
For row = 0 To map.GetUpperBound(1)
For col = 0 To map.GetUpperBound(0)
Console.Write(map(col, row) + ":")
Next col
Console.WriteLine()
Next row
End If
英文:
Here is a simple example showing how to use the first row to decide how many columns your file has. We store the array in (column, row)
order because Redim Preserve
only works on the final index of the array (and we are more likely to add rows than columns).
Dim filename = "C:\Junk\example.csv"
Dim lines = System.IO.File.ReadAllLines(filename)
If lines.Length > 0 Then
Dim colCount = Split(lines(0), ",").Length
Dim rowCount = lines.Length
Dim map(colCount - 1, rowCount - 1)
For row = 0 To rowCount - 1
Dim values = Split(lines(row), ",", colCount)
For col = 0 To colCount - 1
map(col, row) = values(col)
Next col
Next row
'display results
For row = 0 To map.GetUpperBound(1)
For col = 0 To map.GetUpperBound(0)
Console.Write(map(col, row) + ":")
Next col
Console.WriteLine()
Next row
End If
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论