I tried searching and didn't have any success in fixing my problem so I tried finding my own solution.
First I found max (Max) value (min value is always 1), then I set loop to search value by value, but something is wrong with my loop.
For i As Integer = 1 To Max
For y As Integer = 0 To DataGridView1.Rows.Count - 1
If DataGridView1.Rows(y).Cells(0).Value = i Then
Else
builder2.Append(i & ",")
End If
Next
Next
To me loop looks OK but it's not working. If value i is found do nothing if it's not found add i to stringbuilder, and so on until it reaches Max value. But whatever combination I've tried I get some weird results.
Numbers are sorted from lowest to highest.
I've also extracted all values from DGV column to comma delimited string if it's easier that way...
EDIT :
Just for experimenting with that loop I've put i = 40 to 50 (to reduce the range). I know that missing values in DGV column are 40-46 and 59.
This is what I've got with loop above :
You can use LINQ to find missing numbers quite easily. You just need to get the existing numbers into a List, and then you can use Max() to find the largest number, and Except() to find the missing ones.
I put a DGV named DataGridView1 with one column, a button named bnPopulateDGV, and a button named bnFindMissingNumbers on a new Windows Form, and used the following code (with Option Infer On):
Private Sub bnPopulateDGV_Click(sender As Object, e As EventArgs) Handles bnPopulateDGV.Click
DataGridView1.Rows.Clear()
Dim seq1 = Enumerable.Range(1, 100).ToList()
Dim rand As New Random
' knock some out
For i = 1 To 5
seq1.RemoveAt(rand.Next(0, 50))
Next
For Each s In seq1
DataGridView1.Rows.Add(New String() {s.ToString()})
Next
End Sub
Private Sub bnFindMissingNumbers_Click(sender As Object, e As EventArgs) Handles bnFindMissingNumbers.Click
Dim existingNumbers As New List(Of Integer)
For Each r As DataGridViewRow In DataGridView1.Rows
existingNumbers.Add(CInt(r.Cells(0).Value))
Next
Dim min = 1
Dim max = existingNumbers.Max()
Dim missingNumbers = Enumerable.Range(min, max - min + 1).Except(existingNumbers)
MsgBox("Missing: " & String.Join(", ", missingNumbers))
End Sub
Related
I have a csv file having say 50 columns. its not always the case that all these column names are unique. so converting this in to a data table is not possible some times directly.
so my idea is ,
ignore column names and read csv
get first row (which are actually column names) .
convert it into a list of string .
find duplicates from this list. lets say i have 5 duplicates
below is the algorithm which will do the job , before that counter shuld be -1
for all dupe in duplicate items
{
for all str in string array
{
if (str is eq to dupe)
counter = counter + 1
if counter > 0
str = str + counter
}
}
Now write back in to the csv Row(0) with new string array.
then change the column names of the data table as Row(0) and now delete the first row.
i know this is extremely in-efficient. can some one suggest a better way ?
Instead of trying to find the duplicate column names just assign a number at the end of each field name. I used the TextFieldParser class. Available in Namespace: Microsoft.VisualBasic.FileIO See https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.fileio.textfieldparser?view=netcore-3.1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim TFP As New TextFieldParser("C:\Users\maryo\Desktop\TestCSV.csv")
TFP.Delimiters = {","}
Dim FieldNames = TFP.ReadFields
For i = 0 To FieldNames.Length - 1
FieldNames(i) &= i.ToString
Next
Dim dt As New DataTable
For Each FieldName In FieldNames
dt.Columns.Add(FieldName)
Next
While Not TFP.EndOfData
Dim currentRow = TFP.ReadFields()
dt.Rows.Add(currentRow)
End While
DataGridView1.DataSource = dt
End Sub
i am a beginner in vb. i have a datagridview which the data extract from excel file. My data look like this
. I want to create a column chart where x-axis is Department and y-axis is total of status ticket that is open and close.Below is my code which i have stuck and i know i get errors but this is the idea.
i want the result like this
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Me.Chart1.Series("Open").Points.AddXY("Finance", value)
Me.Chart1.Series("Open").Points.AddXY("ITMS", value)
Me.Chart1.Series("Open").Points.AddXY("RV", value)
Me.Chart1.Series("Open").Points.AddXY("Security", value)
Me.Chart1.Series("Close").Points.AddXY("Finance", value)
Me.Chart1.Series("Close").Points.AddXY("ITMS", value)
Me.Chart1.Series("Close").Points.AddXY("RV", value)
Me.Chart1.Series("Close").Points.AddXY("Security", value)
For Count As Integer = 0 To DataGridView1.Rows.Count - 2
Chart1.Series("Open").Points.AddXY(DataGridView1.Item(1, Count).Value, DataGridView1.Item(1, Count).Value)
Chart1.Series("Close").Points.AddXY(DataGridView1.Item(1, Count).Value, DataGridView1.Item(1, Count).Value)
Next
End Sub
End Class
From what I can decipher from the pictures of the data and the chart… you want the number of “open-close” tickets from “Finance” for the first two data points in the chart. The other points are ITMS, RV and Security “departments.” The problem with the posted code is that the current loop is not “adding” the “open” tickets or “closed” tickets for each department. The code is simply “adding” another point to the chart instead of “adding 1” to the existing point.
Tracing the posted for loop using the picture of the grid data, this will add a total of nine (9) points in the chart, the “SAME” nine points are in both the Open/Close” series. However, since departments like “Finance” have three (3) points with the same value, this will display in the chart as three (3) separate “Finance” “departments” … it is here that you need to “add” 1 to the value of the existing “Finance-open/close” point and not simply add “another” “Finance-open/close” point.
The code will need to loop through the grids rows and accumulate the total number of rows that have “Finance” AND “Open”, “Finance” AND “Close”, “ITMS” AND “Open” … etc. This will give you the charts “y” values for each department-open/close. Given this, one possible solution is to write a method that takes two string parameters (department, status) and returns an integer that contains the numbers of rows that match “both” the department and status. These would become the data points for the chart. In this example, you would only be adding eight (8) data points, One for “Finance” “Open” another for “Finance” “Close” … etc... I hope that makes sense.
Below is a simple loop through the grids rows that accumulates the eight points. The method described above is not necessarily the best approach if the data set is large. The described method would loop through the grid a total of eight (8) times. Once for “Finance” and “Open”, another loop through the grid to get “Finance” “Close” … etc. The code below loops through the grid only “once”, however this approach requires the addition of the 8 variables. Pick your poison… hope this helps.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' 8 variables to hold the totals
Dim FinanceOpenCount = 0
Dim FinanceCloseCount = 0
Dim ITMSOpenCount = 0
Dim ITMSCloseCount = 0
Dim RVOpenCount = 0
Dim RVCloseCount = 0
Dim SecurityOpenCount = 0
Dim SecurityCloseCount = 0
' loop through each row and "ADD" 1 to the proper variables
For Each row As DataGridViewRow In DataGridView1.Rows
Select Case row.Cells("Department").Value
Case "Finance"
If (row.Cells("Status").Value = "Open") Then
FinanceOpenCount += 1
Else
FinanceCloseCount += 1
End If
Case "ITMS"
If (row.Cells("Status").Value = "Open") Then
ITMSOpenCount += 1
Else
ITMSCloseCount += 1
End If
Case "RV"
If (row.Cells("Status").Value = "Open") Then
RVOpenCount += 1
Else
RVCloseCount += 1
End If
Case "Security"
If (row.Cells("Status").Value = "Open") Then
SecurityOpenCount += 1
Else
SecurityCloseCount += 1
End If
End Select
Next
' add the points to the chart
Chart1.Series("Open").Points.Clear()
Chart1.Series("Close").Points.Clear()
Chart1.Series("Open").Points.AddXY("Finance", FinanceOpenCount)
Chart1.Series("Close").Points.AddXY("Finance", FinanceCloseCount)
Chart1.Series("Open").Points.AddXY("ITMS", ITMSOpenCount)
Chart1.Series("Close").Points.AddXY("ITMS", ITMSCloseCount)
Chart1.Series("Open").Points.AddXY("RV", RVOpenCount)
Chart1.Series("Close").Points.AddXY("RV", RVCloseCount)
Chart1.Series("Open").Points.AddXY("Security", SecurityOpenCount)
Chart1.Series("Close").Points.AddXY("Security", SecurityCloseCount)
End Sub
Multiple looping method described above.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Chart2.Series("Open").Points.Clear()
Chart2.Series("Close").Points.Clear()
Chart2.Series("Open").Points.AddXY("Finance", GetDeptStatusCount("Finance", "Open"))
Chart2.Series("Open").Points.AddXY("ITMS", GetDeptStatusCount("ITMS", "Open"))
Chart2.Series("Open").Points.AddXY("RV", GetDeptStatusCount("RV", "Open"))
Chart2.Series("Open").Points.AddXY("Security", GetDeptStatusCount("Security", "Open"))
Chart2.Series("Close").Points.AddXY("Finance", GetDeptStatusCount("Finance", "Close"))
Chart2.Series("Close").Points.AddXY("ITMS", GetDeptStatusCount("ITMS", "Close"))
Chart2.Series("Close").Points.AddXY("RV", GetDeptStatusCount("RV", "Close"))
Chart2.Series("Close").Points.AddXY("Security", GetDeptStatusCount("Security", "Close"))
End Sub
Private Function GetDeptStatusCount(department As String, status As String) As Int32
Dim count = 0
For Each row As DataGridViewRow In DataGridView1.Rows
If (row.Cells("Department").Value = department And row.Cells("Status").Value = status) Then
count += 1
End If
Next
Return count
End Function
"Write a program which reads in a start and an end value. The program then stores all the even numbers between these two values (inclusive) in an array. The user is then asked to select a number (n), the program should output the nth even number"
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
number1 = InputBox("Enter first number")
number2 = InputBox("enter second number")
Any guidance on this would be much appreciated, I'm completely lost.
Ok, the edit is making more sense to me now. You were on the right track getting the first three inputs. Then we neeed to do 2 things to our inputs:
1) Get the even numbers within the range the user has given us
2) Return the nth term if it exists
I would approach the problem like this:
'Get our inputs
Dim number1 As Integer = CInt(InputBox("Enter first number"))
Dim number2 As Integer = CInt(InputBox("Enter second number"))
Dim nthTerm As Integer = CInt(InputBox("Enter Nth Term"))
Dim evenNumbers As New List(Of Integer)
'Now, we want to get a list of all the even numbers within n1 to n2 range
For i As Integer = number1 To number2
'if the number divided by 2 has a remainder of 0, then it's an even number
If i Mod 2 = 0 Then evenNumbers.Add(i)
Next
'Now that we have all the even #s, try to return the nth one as long as it exists
Try
'We substract 1 from the nthTerm entered by used to account for list's 0-based index
MsgBox(evenNumbers(nthTerm - 1).ToString)
Catch ex As Exception
MsgBox("Nth Term out of bounds")
End Try
I have a table named users which has the following columns in it
User_id,user_name,user_pwd,First_Name,Middle_Name,Last_Name and user_type.
I have dataset named dst and created a table called user in the dataset. Now I want to populate listbox with user_Name, First_Name, Last_name of each and every row in the table user.
I am able to add one column value at a time but not getting how to add multiple column values of each row to listbox
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(row("User_Name"))
Next
Above code works perfectly but I also want to add First_name as well as last_name to the list box at the same time.
Use same approach as you have, but put all values you want in one string.
Dim dt As DataTable = Dst.Tables("user")
For Each row As DataRow In dt.Rows
Dim sItemTemp as String
sItemTemp = String.Format("{0},{1},{2}", row("User_Name"), row("First_Name"), row("Last_Name"))
lstUsers.Items.Add(sItemTemp)
Next
String.Format() function will call .ToString() on all parameters.
In this case if row(ColumnName) is NULL value then .ToString() return just empty string
You have 2 choices:
Using the ListBox:
To use the ListBox, set the font to one that is fixed width like courier new (so that the columns line up), and add the items like this:
For Each row As DataRow In dt.Rows
lstUsers.Items.Add(RPAD(row("User_Name"),16) & RPAD(row("First_Name"),16) & RPAD(row("Last_Name"),16))
Next
The RPAD function is defined like this:
Function RPAD(a As Object, LENGTH As Object) As String
Dim X As Object
X = Len(a)
If (X >= LENGTH) Then
RPAD = a : Exit Function
End If
RPAD = a & Space(LENGTH - X)
End Function
Adjust the LENGTH argument as desired in your case. Add one more for at least one space. This solution is less than ideal because you have to hard-code the column widths.
Use a DataGridView control instead of a ListBox. This is really the best option, and if you need, you can even have it behave like a ListBox by setting the option to select the full row and setting CellBorderStyle to SingleHorizontal. Define the columns in the designer, but no need to set the widths - the columns can auto-size, and I set that option in the code below. if you still prefer to set the widths, comment out the AutoSizeColumnsMode line.
The code to set up the grid and add the rows goes like this:
g.Rows.Clear() ' some of the below options are also cleared, so we set them again
g.AutoSizeColumnsMode = DataGridViewAutoSizeColumnMode.AllCells
g.CellBorderStyle = DataGridViewCellBorderStyle.SingleHorizontal
g.SelectionMode = DataGridViewSelectionMode.FullRowSelect
g.AllowUserToAddRows = False
g.AllowUserToDeleteRows = False
g.AllowUserToOrderColumns = True
For Each row As DataRow In dt.Rows
g.Rows.Add(row("User_Name"), row("First_Name"), row("Last_Name"))
Next
You might solved your problem by now but other users like me might have issue with it.
Above answers given worked for me even but I found a same answer in a simple way according to what I want..
cmd = New SqlCommand("select User_Name, First_Name, Last_Name from User")
Dim dr As SqlDataReader = cmd.ExecuteReader(YourConnectionString)
If dr.HasRows Then
Do While dr.Read
lst.Items.Add(dr.Item(0).ToString & " " & dr.Item(1).ToString & " " & dr.Item(2).ToString)
Loop
End If
This worked for me, maybe wrong way but I found it simple :)
May I suggest you use a ListView control instead of Listbox?
If you make the switch, here's a sample subroutine you could use to fill it up with the data you said you want. Adapt it the way you like; there's much room for improvement but you get the general idea:
Public Sub FillUserListView(lstUsers As ListView, Dst As DataSet)
Dim columnsWanted As List(Of String) = New List(Of String)({"User_Name", "First_Name", "Last_Name"})
Dim dt As DataTable = Dst.Tables("user")
Dim columns As Integer = 0
Dim totalColumns = 0
Dim rows As Integer = dt.Rows.Count
'Set the column titles
For Each column As DataColumn In dt.Columns
If columnsWanted.Contains(column.ColumnName) Then
lstUsers.Columns.Add(column.ColumnName)
columns = columns + 1
End If
totalColumns = totalColumns + 1
Next
Dim rowObjects(columns - 1) As ListViewItem
Dim actualColumn As Integer = 0
'Load up the rows of actual data into the ListView
For row = 0 To rows - 1
For column = 0 To totalColumns - 1
If columnsWanted.Contains(dt.Columns(column).ColumnName) Then
If actualColumn = 0 Then
rowObjects(row) = New ListViewItem()
rowObjects(row).SubItems(actualColumn).Text = dt.Rows(row).Item(actualColumn)
Else
rowObjects(row).SubItems.Add(dt.Rows(row).Item(actualColumn))
End If
lstUsers.Columns.Item(actualColumn).Width = -2 'Set auto-width
actualColumn = actualColumn + 1
End If
Next
lstUsers.Items.Add(rowObjects(row))
Next
lstUsers.View = View.Details 'Causes each item to appear on a separate line arranged in columns
End Sub
I created a custom GridView (actually a RadGrid) which does roughly the following.
Initialize GridView formatting
Setup Columns (depending on type of data to be displayed)
Populate the rows
When Instantiating this GridView, and adding it to my page, I want the first column to contain a "rowspan" attribute on the first row of repeated, but similar data. The "rowspan" value should be equal to the number of similar rows following it. In this way I hope to make the final view cleaner.
The logic for this, I figure, should take place while populating the rows. Initially I add rows to a DataTable and then bind it to the GridView as the final step.
Here's the general logic I was attempting, but it didn't work for me. What am I doing wrong?
Dim dt As New DataTable() 'Has three default columns
For Each d In Documents 'MAIN ITEM (First Column Data)
Dim rowspan As Integer
rowspan = 0
For Each f In Files
If rowspan = 0 Then
Me.dt.Rows.Add(New Object() {d.Title, f.Language, f.FileSize})
'THIS DOESN'T WORK!
Me.dt.Columns(0).ExtendedProperties.Item("rowspan") = rowspan.ToString()
Else
Me.dt.Rows.Add(New Object() {Nothing, f.Language, f.FileSize})
End If
rowspan += 1
Next
Next
Also keep in mind that the this is dumped into a DataView which is sorted by the first column, so I would imagine it must actually be sorted first, then somehow count the rows for each "like" first column, then set the "rowspan" value for the first row of that column equal to the number of rows belonging to it.
Does this make sense? Here is an ideal example of what I would like to accomplish in the layout:
Try this.
Protected Sub DemoGrid_PreRender(sender As Object, e As System.EventArgs) Handles DemoGrid.PreRender
MergeRowsWithSameContent(sender)
End Sub
Public Sub MergeRowsWithSameContent(gvw As GridView)
For rowIndex As Integer = gvw.Rows.Count - 2 To 0 Step -1
Dim row As GridViewRow = gvw.Rows(rowIndex)
Dim previousRow As GridViewRow = gvw.Rows(rowIndex + 1)
For i As Integer = 0 To row.Cells.Count - 1
If row.Cells(i).Text = previousRow.Cells(i).Text Then
row.Cells(i).RowSpan = If(previousRow.Cells(i).RowSpan < 2, 2, previousRow.Cells(i).RowSpan + 1)
previousRow.Cells(i).Visible = False
End If
Next
Next
End Sub
P.S: Shameless port of this wonderful code I have been using for years.