Is it possible to convert DataRow to arraylist? - vb.net

I have a DataRow. Is there a way to convert it into an arraylist? I need to convert it to an arraylist because I want to pass it to a function which compares two arrays and returns false if they are not the same.
foo(datarow, arraylist)
Public Function foo(ByVal arr1 as Arraylist, ByVal arr2 as ArrayList) as Boolean
Compare and return false if they are not the same
End Function
So, how do I convert datarow to arraylist so that I can pass it to that function.

I agree that you should only convert to ArrayList if necessary, but you certainly can.
Dim al As New ArrayList
Dim dt As New DataTable
dt.Columns.Add("f")
dt.Columns.Add("n")
Dim dr As DataRow
dr = dt.NewRow
dr.Item(0) = "First"
dr.Item(1) = "Name"
dt.Rows.Add(dr)
For Each row As DataRow In dt.Rows
For Each column As DataColumn In dt.Columns
al.Add(row.Item(column.ColumnName))
Next
MessageBox.Show(al.Item(0).ToString & " " & al.Item(1).ToString)
Next

Related

how to create CSV string from DataTable in VB.NET?

I'm fetching data from database as a DataTable and need to convert into CSV string in VB.NET.
Create a generic method with DataTable, CSV Headers, DataTable Columns parameters:
Private Function CSVBuilder(dt As DataTable, headers As List(Of String), columns As List(Of String)) As String
Dim sCSV = New StringBuilder(String.Join(",", headers))
sCSV.Append(Environment.NewLine)
Dim view As New DataView(dt)
Dim tDt As DataTable = view.ToTable(True, columns.ToArray)
For Each row As DataRow In tDt.Rows
'-- Handle comma
sCSV.Append(String.Join(",", (From rw In row.ItemArray Select If(rw.ToString.Trim.Contains(","), String.Format("""{0}""", rw.ToString.Trim), rw.ToString.Trim))))
sCSV.Append(Environment.NewLine)
Next
Return sCSV.ToString
End Function
And then call in your code to get CSV string:
CSVBuilder(dataTable,
New List(Of String) From {"Header Column 1", "Header Column 2", ...},
New List(Of String) From {"DataTableColumn1", "DataTableColumn2", ...})
In response to the comment, since this wouldn't fit in that space:
Private Function CSVBuilder(dt As DataTable) As String
Dim sCSV As New StringBuilder()
'Headers
Dim delimeter As String = ""
For Each col As String In dt.Columns.Select(Func(col) col.ColumnName)
If col.Contains(",") Then col = """" & col & """"
sCSV.Append(delimeter).Append(col)
delimeter = ","
Next
sCSV.AppendLine()
For Each row As DataRow In tDt.Rows
sCSV.AppendLine(String.Join(",", (From rw In row.ItemArray Select If(rw.ToString.Trim.Contains(","), String.Format("""{0}""", rw.ToString.Trim), rw.ToString.Trim))))
Next
Return sCSV.ToString
End Function
Now, I did remove this code:
Dim view As New DataView(dt)
Dim tDt As DataTable = view.ToTable(True, columns.ToArray)
But I wouldn't do this as part of the CSVBuilder() method. If you want to project a specific view of a table, I would do that separately from creating the CSV data. You could make a separate method for it:
Public Function GetProjection(dt As DataTable, columns As IEnumerable(Of String)) As DataTable
Dim view As New DataView(dt)
Return view.ToTable(True, columns.ToArray())
End Function
And then you call them together like this:
Dim dt As DataTable = '.... original table here
Dim columns() As String = '... the columns you want
Dim csv As String = CSVBuilder(GetProjection(dt, columns))
or like this:
Dim dt As DataTable = '.... original table here
Dim columns() As String = '... the columns you want
Dim dt1 = GetProjection(dt, columns)
Dim csv As String = CSVBuilder(dt1)
This is called Currying, and it's a good thing to do.
Finally, I'll repeat my suggestion to think in terms of writing to a stream. Long strings with repeated append operations can cause real problems for the .Net garbage collector. Using StringBuilder can help, but won't fully eliminate these problems. Writing to a Stream, which is often connected to a file on disk, gives you the opportunity to completely eliminate this issue. Plus, it will likely save you work later on.

Dynamic code execution: String -> Runtime code VB.net

I'm trying to execute some code inside a string in runtime. I.E.
Dim code As String = "IIf(1 = 2, True, False)"
How do i run the code inside code string ?
As #ElektroStudios said - the proper way to do this is to use the CodeDom compiler, but this is a bit overkill for something as simple as this.
You can sort of cheat and harness the power of a DataColumn Expression
So for example:
Dim formula = "IIF(Condition = 'Yes', 'Go', 'Stop')"
Dim value As String = "Yes"
Dim result As String
'add a columns to hold the value
Dim colStatus As New DataColumn
With colStatus
.DataType = System.Type.GetType("System.String")
.ColumnName = "Condition"
End With
'add a column to compute the expression
Dim colExp As New DataColumn
With colExp
.DataType = System.Type.GetType("System.String")
.ColumnName = "Expression"
.Expression = formula
End With
'create a table and add the columns
Dim dt As New DataTable
With dt.Columns
.Add(colStatus)
.Add(colExp)
End With
'now add a row and set the condition to the value we have
Dim row As DataRow = dt.NewRow
row.SetField(Of String)("Condition", value)
dt.Rows.Add(row)
'now read back the computed value based on the expression being evaluated
result = row.Field(Of String)("Expression")
MessageBox.Show(result)
You could wrap all this up into a more generic function like this:
Public Function EvaluateExpression(Of T, K)(input As T, formula As String) As K
'add a columns to hold the value
Dim colStatus As New DataColumn
With colStatus
.DataType = GetType(T)
.ColumnName = "Condition"
End With
'add a column to compute the expression
Dim colExp As New DataColumn
With colExp
.DataType = GetType(K)
.ColumnName = "Expression"
.Expression = formula
End With
'create a table and add the columns
Dim dt As New DataTable
With dt.Columns
.Add(colStatus)
.Add(colExp)
End With
'now add a row and set the condition to the value we have
Dim row As DataRow = dt.NewRow
row.SetField(Of T)("Condition", input)
dt.Rows.Add(row)
'now read back the computed value based on the expression being evaluated
Return row.Field(Of K)("Expression")
End Function
So then you can call it like this:
Dim result = EvaluateExpression(Of Integer, Boolean)(1, "IIF(Condition = 1, True, False)")

Trimming a datagridview duplicat rows except the recent one

i'm in VS2008 Studio, i have this datagridview with multiple columns which the last column contains a date and time value.
lot's of rows are pretty the same except by they're date column.
what i wanted to do is to trim the whole datagridview duplicate rows except they're most recent ones based on they're date column.
i have sth like this:
Administrator,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 - 23:11:59
Administrator,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 -
21:11:59
Administrator,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 - 22:11:59
Administrator,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 - 20:11:59
Administrator,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 - 11:11:59
Everyone ,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 - 17:11:59
Everyone ,192.168.137.221,2,file://C:\WMPub\WMRoot\industrial.wmv , 07.Jul.2014 - 14:11:59
the output i want should be like this:
Administrator 192.168.137.221 2 file://C:\WMPub\WMRoot\industrial.wmv 07.Jul.2014 - 23:11:59
Everyone 192.168.137.201 2 file://C:\WMPub\WMRoot\industrial.wmv 07.Jul.2014 - 17:11:59
....
please consider "," as column seprators! (i dont know how to draw a table here, sorry again)!
i have this snippet that trim the duplicate lines in a datagridview but it lacks preserving the latest entry:
Public Function RemoveDuplicateRows(ByVal dTable As DataTable, ByVal colName As String) As DataTable
Dim hTable As New Hashtable()
Dim duplicateList As New ArrayList()
For Each dtRow As DataRow In dTable.Rows
If hTable.Contains(dtRow(colName)) Then
duplicateList.Add(dtRow)
Else
hTable.Add(dtRow(colName), String.Empty)
End If
Next
For Each dtRow As DataRow In duplicateList
dTable.Rows.Remove(dtRow)
Next
Return dTable
End Function
what should i do?
thanks in advance
Here is some code that illustrates the approach:
Dim dict As New dictionary(Of String, DataRow)
For Each dtRow As DataRow In dTable.Rows
Dim key As String = dtRow("column1") + "," + dtRow("column2") ' + etc.
Dim dictRow As DataRow = Nothing
If dict.TryGetValue(key, dictRow) Then
'check and update date
'you can skip this part, if your data is sorted
If dtRow("dateColumn") > dictRow("dateColumn") Then
dictRow("dateColumn") = dtRow("dateColumn")
End If
Else
dict.Add(key, dtRow)
End If
Next
In the end dict contains the rows you need, you can get them via dict.Values.ToArray()
EDIT: I found the error - dictRow should be dtRow in the above code (now fixed). Then it should work. Here is a full version of self contained example (console app), since I wrote it anyway - focus on RemoveDuplicates, the rest is just prepwork:
Sub Main()
Dim dt As New DataTable
With dt.Columns
.Add("PublishingPoint")
.Add("Username")
.Add("IP")
.Add("Status")
.Add("Req URL")
.Add("Last seen", GetType(Date))
End With
'this populates the initial data table, use your method
Dim _assembly As Assembly = Assembly.GetExecutingAssembly()
Dim _textStreamReader As New StreamReader(_assembly.GetManifestResourceStream("ConsoleApplication16.data.csv"))
While Not _textStreamReader.EndOfStream
Dim sLine As String = _textStreamReader.ReadLine().TrimEnd
If String.IsNullOrEmpty(sLine) Then Exit While
Dim values() As String = sLine.Split(",")
Dim newRow As DataRow = dt.NewRow
For iColumnIndex As Integer = 0 To dt.Columns.Count - 1
Dim columnName As String = dt.Columns(iColumnIndex).ColumnName
newRow.Item(columnName) = values(iColumnIndex)
Next
dt.Rows.Add(newRow)
End While
Console.WriteLine("Old count: " & dt.Rows.Count)
Dim newDt As DataTable = RemoveDuplicates(dt, "Last seen")
Console.WriteLine("New count: " & newDt.Rows.Count)
Console.ReadLine()
End Sub
Private Function RemoveDuplicates(dt As DataTable, colName As String) As DataTable
Dim keyColumnNames As New List(Of String)
Dim exceptColumnsHash As New HashSet(Of String)({colName})
For Each col As DataColumn In dt.Columns
Dim columnName As String = col.ColumnName
If Not exceptColumnsHash.Contains(col.ColumnName) Then
keyColumnNames.Add(columnName)
End If
Next
Dim dict As New Dictionary(Of String, DataRow)
For Each dtRow As DataRow In dt.Rows
Dim keyColumnValues As New List(Of String)
For Each keyColumnName In keyColumnNames
keyColumnValues.Add(dtRow.Item(keyColumnName))
Next
Dim key As String = String.Join(",", keyColumnValues)
Dim dictRow As DataRow = Nothing
If dict.TryGetValue(key, dictRow) Then
If dtRow(colName) > dictRow(colName) Then
dictRow(colName) = dtRow(colName)
End If
Else
dict.Add(key, dtRow)
End If
Next
Dim dtReturn As DataTable = dt.Clone
For Each dtRow As DataRow In dict.Values
dtReturn.ImportRow(dtRow)
Next
Return dtReturn
End Function
To make this code run, you need to manually add a file to the project and set build action to "Embedded resource".

Stored list of array using For Each loop

I want to store the "zone_check_value" to a array of string then while inserting into array i will check the array of string if the next value is repeated or have duplicate.
Example.
1st Example
1st loop = zone_check_value = ZD1/01/2014
2nd loop = zone_check_value = ZD1/01/2014
2nd Example
1st loop = zone_check_value = ZD1/01/2014
2nd loop = zone_check_value = ZD2/02/2014
3rd loop = zone_check_value = ZD1/01/2014
Code:
For Each dt As DataTable In xls.Tables
Dim array_of_string as String() 'i want to put the value in here
For Each dr As DataRow In dt.Rows
Dim zone_destination As String = dr(2).ToString
Dim affected_date As String = dr(7).ToString
Dim zone_check_value = zone_destination + affected_date
''''''How can i store zone_check_value in a string array?
Next
Next
EDIT
What if i add select case in my loop? the array_of_string value become NULL. I need to check the value of the current value in array_of_string .
Example Code
For Each dt As DataTable In xls.Tables
Dim array_of_string as String() 'i want to put the value in here
select Case dt.tablename
case "Sheet1"
For Each dr As DataRow In dt.Rows
Dim zone_destination As String = dr(2).ToString
Dim affected_date As String = dr(7).ToString
Dim zone_check_value = zone_destination + affected_date
''''''How can i store zone_check_value in a string array?
Next
case "Sheet 2"
For Each dr As DataRow In dt.Rows
Dim check_value as Boolean = array_of_string.Contains(dr(0).ToString)
'but when i got in sheet 2 the array_of_string is null
Next
Next
The easiest way is to use a List(Of String).
For Each dt As DataTable In xls.Tables
Dim array_of_string as List(Of String) = New List(Of String) 'i want to put the value in here
For Each dr As DataRow In dt.Rows
Dim zone_destination As String = dr(2).ToString
Dim affected_date As String = dr(7).ToString
Dim zone_check_value = zone_destination & affected_date
''''''How can i store zone_check_value in a string array?
array_of_string.Add(zone_check_value)
Next
''' Now if you really need it in array form you can cast it via:
''' Dim values() As String = array_of_string.ToArray()
Next
You might even consider:
For Each dt As DataTable In xls.Tables
Dim values As List(Of String) = New List(Of String)
dt.Rows.ForEach( Sub(item) values.Add(item(2).ToString & item(7).ToString) )
''' Now do something with values.
Next
Either way, make sure you always use the string concatenation operator & to concatenate strings. The arithmetic addition operator + will cause you problems from time to time if you use it on strings.

How to add List as value in Hashtable

In vb.net If I have HashTable,key is integer and the value is a list of integers, how to append integers to the value of a given key,
I have tried it but each time I found the integer last added only, (the list only has the last item added).
Here is my code , where dt is DataTable object
Dim dt = report.getEvaluationReportByObjectiveGroupId(29)
Dim data As New Hashtable()
Dim dataEntry As DictionaryEntry
Dim res As String
For Each row As DataRow In dt.Rows
Dim strYear = row.Item("Year")
Dim strData = row.Item("EmpCount")
If data.ContainsKey(strYear) Then
Dim newCountArr As List(Of Int32) = DirectCast(data(strYear), List(Of Int32))
' newCountArr.AddRange(data(strYear))
newCountArr.Add(strData)
' data.Remove(strYear)
' data.Add(strYear, newCountArr)
Else
Dim countArr As New List(Of Integer)
countArr.Add(strData)
data.Add(strYear, countArr)
End If
' data.Add(strYear, strData)
Next row
I would suggest to use the strongly typed Dictionary(Of Int32, List(Of Int32)) instead, it works similar. But anyway, here's the HashTable approach:
Dim table = New Hashtable
Dim list = New List(Of Int32)
For i = 1 To 999
list.Add(i)
Next
table.Add(1, list)
' somewhere else you want to read the list for a given key (here 1) '
Dim list1 As List(Of Int32) = DirectCast(table(1), List(Of Int32))
list.Add(1000) ' add another integer to the end of the list '
' note: you don't need to add the list to the HashTable again '
Edit: Since you've posted your code, here's the corrected:
For Each row As DataRow In dt.Rows
Dim strYear = row.Field(Of Int32)("Year")
Dim strData = row.Field(Of Int32)("EmpCount")
Dim list As List(Of Int32)
If data.ContainsKey(strYear) Then
list = DirectCast(data(strYear), List(Of Int32))
Else
list = New List(Of Int32)
data.Add(strYear, list)
End If
list.Add(strData)
Next row