I have a datatable which I keep cleaning and I put in values into it. So once in the execution time the data in the table looks like this
1211 A B C
1212 D E F
I have a datatable dt_new and add both these rows.(because first column is distinct).
Some times the data ends up like this
1213 I J K
1213 L M N
In this case I want to NOT add any of the row to my dt_new.(because first column is same for both rows)
How do i do this? Looks simple but i am ending up with varied results. I am checking by iterating the table and checking for first column but not getting result.
If you need more info, please ask.Thanks
For Each drTempRow As DataRow In dtTemp.Rows
Dim intCounter As Integer = 0
Dim intCounterEqual As Integer = 0
For Each drInnerRow As DataRow In dtTemp.Rows
If drTempRow("CustomerID") <> drInnerRow("CustomerID") Then
intCounter += 1
Else
intCounterEqual += 1
End If
Next
If intCounterEqual = 1 AndAlso intCounter <> dtTemp.Rows.Count - 1 Then
Dim drNewRow As DataRow = dt_new.NewRow()
drNewRow.ItemArray = drTempRow.ItemArray
dt_new.Rows.Add(drNewRow)
End If
Next
You can achieve it this way without a nested loop:
Remember: You must sort your dtTemp by CustomerID first, before use this code.
Dim dt_new As DataTable = dtTemp.Clone()
Dim previousId As String = ""
For Each drTempRow As DataRow In dtTemp.Rows
If Not drTempRow("CustomerID").ToString().Equals(previousId) Then
dt_new.ImportRow(drTempRow)
End If
previousId = drTempRow("CustomerID").ToString()
Next
Related
I have a data set with several hundred rows. Most rows have complete information, but in some cases two rows share the same key while some attributes are repeated, others are not. Here is an example:
Key Campaign Message Stat1 Stat2 Stat3 Stat4
123 Fun yay 1 2
123 temp yay 3 4
Intended result
123 Fun yay 1 2 3 4
Issues:
Needs to search the entire dataframe of hundreds of records, most of which are not duplicates. Ignore the non-duplicates
Has to specify that when combining rows to accept the Campaign data that is NOT "temp"
All other columns where data matches is ok
Columns where one value is null will result in the non-null value being used in the new record
I am open to solutions in R, SQL or excel (vba)
Appreciate any help!
Turned out to be a bit more involved than I thought, but here it is. I am using a collection to merge duplicate keys. Change IGNORE_TEMP constant to include or exclude temp records.
Sub mergeNonNulls()
' change this constant to ignore or include temp results
Const IGNORE_TEMP As Boolean = True
' temporary store of merged rows
Dim cMerged As New Collection
' data part of the table
Dim data As Range
Set data = ActiveSheet.[a2:g3]
Dim rw As Range ' current row
Dim r As Range ' temporary row
Dim c As Range ' temporary cell
Dim key As String
Dim arr() As Variant
Dim v As Variant
Dim vv As Variant
Dim i As Long
Dim isChanged As Boolean
For Each rw In data.Rows
key = rw.Cells(1) ' the first column is key
If IGNORE_TEMP And rw.Cells(2) = "temp" Then
DoEvents ' pass temp if enabled
Else
If Not contains(cMerged, key) Then
' if this is new key, just add it
arr = rw
cMerged.Add arr, key
Else
' if key exists - extract, merge nulls and replace
arr = cMerged(key)
' iterate through cells in current and stored rows,
' identify blanks and merge data if current is empty
i = 1
isChanged = False
For Each c In rw.Cells
If Len(Trim(arr(1, i))) = 0 And Len(Trim(c)) > 0 Then
arr(1, i) = c
isChanged = True
End If
i = i + 1
Next
' collections in vba are immutable, so if temp row
' was changed, replace it in collection
If isChanged Then
cMerged.Remove key
cMerged.Add arr, key
End If
End If
End If
Next
' output the result
Dim rn As Long: rn = 1 ' output row
Dim numRows As Long
Dim numCols As Long
With ActiveSheet.[a6] ' output start range
For Each v In cMerged
numRows = UBound(v, 1) - LBound(v, 1) + 1
numCols = UBound(v, 2) - LBound(v, 2) + 1
.Cells(rn, 1).Resize(numRows, numCols).Value = v
rn = rn + 1
Next
End With
End Sub
' function that checks if the key exists in a collection
Function contains(col As Collection, key As String) As Boolean
On Error Resume Next
col.Item key
contains = (Err.Number = 0)
On Error GoTo 0
End Function
I have a datatable that I'm looping thru...
For Each drIndicator As DataRow In dtIndicatorsToProcess.Rows
Is there a way to "peek" at the next few rows to determine some things then continue?
Thanks!
You should use the for loop, something as shown below should suitable
For i = 0 To dtIndicatorsToProcess.Rows.Count - 1
Dim drIndicator As DataRow = dtIndicatorsToProcess.Rows(i)
'// Check ahead 2 rows
Dim drRowToCheck As DataRow = dtIndicatorsToProcess(i + 2)
'// Process here
Next
I have one data table in VB page which contain bulk data.In that data table one column named as vType and values in that column is one of Pr defined values such as 'A','B','C','D' etc , which comes from one Datable.
Now I want count of each type at the end.
For ex : CountA = 20,CountB=25 and so on .
Till now I have compared Each value using If condition which is static
For each dr as dataRow in dsType.rows
If dr("vType") = 'A' Then
CountA += 1
ElseIf dr("vType") = 'B' Then
CountB +=1
Next dr
and this If condition will repeat depend upon no of types in that data table (at max 8 fix values) I want to do this in single if condition ( Dynamic if Possible) Can I Count these values and store the same into single varaible? appreciate for you prompt reply.
You can use Linq-To-DataSet and Enumerable.GroupBy + Enumerable.Count on each group:
Dim typeGroups = dsType.AsEnumerable().
GroupBy(Function(row) row.Field(Of String)("vType")).
Select(Function(g) New With{ .Type = g.Key, .Count = g.Count(), .TypeGroup = g })
Note that New With creates an anonymous type in VB.NET with custom properties. So like a class on-the-fly which you can use in the current method.
Now you can enumerate the query with For Each:
For Each typeGroup In typeGroups
Console.WriteLine("Type:{0} Count:{1}", typeGroup.Type, typeGroup.Count)
Next
I cannot use Linq, i need to use simple vb only
Then use a Dictionary:
Dim typeCounts = New Dictionary(Of String, Integer)
For Each row As DataRow In dsType.Rows
Dim type = row.Field(Of String)("vType")
If (typeCounts.ContainsKey(type)) Then
typeCounts(type) += 1
Else
typeCounts.Add(type, 1)
End If
Next
Now you have a dictionary where the key is the type and the value is the count of the rows with this type.
why not getting the pretend result from the db itself?
Like so:
select count(*), vType
from someTable
group by vType
Not so sure about your question .. but this is what I've considered ..
You can make it as Sub ..
Sub AssignIncr(ByVal ds as DataSet,byval sFi as String,byval sCrit as String,ByRef Counter as Integer)
For each dr as dataRow in ds.rows
If dr(sFi) = sCrit Then Counter += 1
Next dr
End Sub
So you may use it by ..
AssignIncr(dsType,"vType","A",CountA)
I am trying to change the list item values of a dropdown list based on values of an other dropdown list. The list values of drpAdult range from 0-9 and list values of drpInfant range from 0-(Value of drpAdult selected).
So, for example, if I select 5 in the drpAdult dropdown, the range of list item values of drpInfant will be from 0-5.
I have written the code below, but it is not populating the values in the drpInfant dropdown, which I am trying to insert on drpAdult_SelectedIndexChanged event.
Protected Sub drpAdult_SelectedIndexChanged(ByVal sender As Object,
ByVal e As EventArgs) Handles drpAdult.SelectedIndexChanged
Dim count As Integer
count = drpAdult.Items.Count
Dim i As Integer
i = 0
While count > 0
i = i + 1
drpInfant.Items.Add(New ListItem(i, i))
count = count - 1
End While
End Sub
What might cause this problem, and how can I resolve it?
Not sure what "is not working" means, but this seems to be easier anyway:
Dim newCount = drpAdult.Items.Count + 1
For i As Int32 = 0 To newCount
Dim newItem As New ListItem(i.ToString, i.ToString)
drpInfant.Items.Add(newItem)
Next
You can try this. I have tested this & working fine:
Protected Sub drpAdult_SelectedIndexChanged(sender As Object, e As EventArgs)
drpInfant.Items.Clear()
Dim count As Integer = drpAdult.SelectedIndex
Dim i As Integer = 0
While count >= 0
drpInfant.Items.Add(New ListItem(i.ToString(), i.ToString()))
i = i + 1
count = count - 1
End While
End Sub
Something along these lines...
drpInfant.Items.Clear()
dim n as Integer
Integer.TryParse(drpAdult.SelectedValue, n)
For i as integer = 1 to n
if n < i Then Exit For 'it's not fun when this condition happens in VB
drpInfant.Items.Add(New ListItem(i, i))
Next
I have Dataset ds filled up with values Until now I was displaying values in GridView. Now I want that all the rows should be columns and columns should be rows.
I have 2 options: Either 1 I can directly convert grid to columns and display it, or
2 I can convert the GridView to html and then write loops to convert. I was trying the 2nd option but I cant figure out how I should do that. Below is my code:
For Each dr In dt.Rows
htmlTable = htmlTable + "<TR>"
For Each dc In dt.Columns
htmlTable = htmlTable + "<TD>" + ds.Tables(0).Columns(j).ToString() + ""
j = j + 1
Next
i = i + 1
Next
With this code I am still getting same as GridView. Please help me for converting rows to columns and vice versa.
It looks like your attempting to write an HTML table from the DataTable in the DataSet, flipping rows and columns. The code you posted has several issues, so I'm using it more as pseudo-code for my answer.
The reason you're getting the same thing (in terms of rows and columns) as the GridView is because you loop through each row, and in each row you loop through all the columns - you're not flipping columns and rows at all.
Try something like this:
Dim htmlTable As StringBuilder = new StringBuilder()
Dim numberRows As Integer = ds.Tables(0).Rows.Count - 1
Dim numberCols As Integer = ds.Tables(0).Columns.Count - 1
htmlTable.Append("<table>")
' Loop through each column first
For i As Integer = 0 To numberCols
htmlTable.Append("<tr>")
' Now loop through each row, getting the current columns value
' from each row
For j As Integer = 0 To numberRows
htmlTable.Append("<td>")
htmlTable.Append(ds.Tables(0).Rows(j)(i))
htmlTable.Append("</td>")
Next
htmlTable.Append("</tr>")
Next
htmlTable.Append("</table>")
' To get the value of the StringBuilder, call ToString()
Dim resultHtml = htmlTable.ToString()
For example, if you have a table like this:
col1 col2 col3
a b c
d e f
g h i
j k l
The result would be:
a d g j
b e h k
c f i l