Retrieve distinct values from datatable using linq vb.net - vb.net

I am trying to retrieve all of the distinct values from a particular column in a datatable. The column name in the datatable is "Count". I have 2240 rows and I have 6 distinct values in the "Count" column. The problem is, when I execute the following code, it is giving me the number of rows rather than the 6 distinct values.
Dim counts = (From row In loadedData
Select row.Item("Count")).Distinct()
For Each i In counts
MsgBox(i)
Next
How can I modify this to retrieve the 6 distinct values, rather than it giving me the total number of rows?

You just have to select the column and use Enumerable.Distinct:
Dim distinctCounts As IEnumerable(Of Int32) = loadedData.AsEnumerable().
Select(Function(row) row.Field(Of Int32)("Count")).
Distinct()
In query syntax(i didn't know that even Distinct is supported directly in VB.NET):
distinctCounts = From row In loadedData
Select row.Field(Of Int32)("Count")
Distinct

You can use ToTable(distinct As Boolean, ParamArray columnNames As String()) method for this.
loadedData.DefaultView.ToTable(True, "Count")
This will return distinct Users for you. You can add multiple column names if you want.
Here is the msdn documentation.
https://msdn.microsoft.com/en-us/library/wec2b2e6(v=vs.110).aspx

you can also apply this logic if you want ,
first sort datatable through columName ,
then apply this logic
dtRecords.DefaultView.Sort = "columnName"
dtRecords = dtRecords.DefaultView.ToTable
Dim totalRecords As Integer = 0
Dim thNameStr As String = filter(dtRecords, "columnName", totalRecords )
Public Shared Function filter(ByVal dtRecords As DataTable, ByVal columnName As String, ByRef totalRecords As Integer) As String
Dim FilterStr As String = ""
Dim eachTotal As Integer = 0
totalRecords = 0
Dim lastName As String = ""
For rCount = 0 To dtRecords.Rows.Count - 1
If lastName <> "" And lastName <> dtRecords.Rows(rCount)("" & columnName) Then
FilterStr &= lastName & " - [" & eachTotal & "]"
eachTotal = 0
totalRecords += 1
End If
lastName = dtRecords.Rows(rCount)("" & columnName)
eachTotal += 1
Next
FilterStr &= lastName & " - [" & eachTotal & "]"
totalRecords += 1
Return FilterStr
End Function

Related

Join string with specific word for RowFilter

I have rowfilter which i use to filter my datasource. I have couple controls which user can pick up checking specific checkboxes either to be used for Rowilter or not. Below code.
Dim ds = CType(dgvAbmessungen.PrimaryGrid.DataSource, DataSet)
Dim dtMain As DataTable = ds.Tables(0)
Dim filterStr As String = String.Empty
Dim byNummer As String = " [Nummer] like '" & txtFilterByNummer.Text.Trim() & "%'"
Dim byUser As String = " [User] = '" + cbUser.Text
Dim byCreateDateFrom As String = " [CreateDate] >= '" + CType(Convert.ToDateTime(calFrom.Value.Date), String)
Dim byCreateDateTo As String = "' ([CreateDate] < '" + CType(Convert.ToDateTime(calTo.Value.Date), String)
'select case checboxes and construct final rowfilter's string
dtMain.DefaultView.RowFilter = filterStr
Checboxes for diffrent controls to be checked:
for Nummer there is checkboxNummer
for User there is checkboxUser
for CreateDateFrom there is checkboxCreateDateFrom
for CreateDateTo there is checkboxCreateDateTo
Target is user checks one or more checboxes and filter should be constructed (string). Problem is i have no idea how to also concat "And" keywords between strings if user check more than one diffrent checboxes.
Currently i try to do it using select case. What could be the most efficient way to do so?
I would use LINQ:
Dim data = dtMain.AsEnumerable()
If checkboxNummer.Checked Then
data = data.Where(Function(row) row.Field(Of String)("Nummer").Contains(txtFilterByNummer.Text.Trim()))
End If
If checkboxUser.Checked Then
data = data.Where(Function(row) row.Field(Of String)("User") = cbUser.Text.Trim())
End If
If CreateDateFrom.Checked Then
data = data.Where(Function(row) row.Field(Of Date)("CreateDate") >= calFrom.Value.Date)
End If
If CreateDateTo.Checked Then
data = data.Where(Function(row) row.Field(Of Date)("CreateDate") < calTo.Value.Date)
End If
If you need the result as DataRow() use data.ToArray(). If you need a DataTable use:
If data.Any() Then dtMain = data.CopyToDataTable()

Select distinct rows and sum columns in DataTable VB.Net 2005

i have a dataTable contains:
ID POCount POTotal
A 1 10
A 2 20
B 4 10
I want to get a result of a new data table as bellow:
ID POCount POTotal
A 3 30
B 4 10
How can i do this using a datatable?
My project is in VB.NET 2005 and i cannot use LINQ method.
What is the best way to do this?
I found a link that kinda near what i want. But it just skip the rows instead of summing up the columns when the id is similar.
http://www.dotnetfunda.com/forums/show/2603/how-to-remove-duplicate-records-from-a-datatable
LINQ is probably better - upgrade to later VS Express - its free!
Here is one approach using a class and a Dictionery
Public Class POSummary
Public Property ID As String
Public Property Count As Integer
Public Property Total As Integer
Sub New(POid As String, POcount As Integer, POtotal As Integer)
ID = POid
Count = POcount
Total = POtotal
End Sub
End Class
Private Sub Button12_Click(sender As Object, e As EventArgs) Handles Button12.Click
Dim pos As New List(Of POSummary)
Dim po As New POSummary("A", 1, 10)
pos.Add(po)
po = New POSummary("A", 2, 20)
pos.Add(po)
po = New POSummary("B", 4, 10)
pos.Add(po)
Debug.Print("--data--")
For Each p As POSummary In pos
Debug.Print(p.ID & " " & p.Count & " " & p.Total)
Next
Dim pd As New Dictionary(Of String, POSummary)
For Each p As POSummary In pos
If Not pd.ContainsKey(p.ID) Then
pd.Add(p.ID, p)
Else
pd(p.ID).Count += p.Count
pd(p.ID).Total += p.Total
End If
Next
Debug.Print("--totals--")
For Each kvp As KeyValuePair(Of String, POSummary) In pd
po = kvp.Value
Debug.Print(po.ID & " " & po.Count & " " & po.Total)
Next
Stop
End Sub

Group DataSet Column Values into Comma Separated String using LINQ

How do I combine column values in a dataset using LINQ into a single string with comma separated values in VB.NET ?
I have one table with following structure
ID Name
728 Jim
728 Katie
728 Rich
How do I combine these into a single row like following
ID Name
728 Jim,Katie,Rich
Please note I am using a LINQ to Dataset so please respond in the applicable syntax.
Here is an example (using LINQ to objects, but should be easy to adjust for LINQ to DataSet):
Class Record
Public Property ID As Integer
Public Property Name As String
Sub New(id As Integer, name As String)
Me.ID = id
Me.Name = name
End Sub
End Class
Sub Main()
Dim recordList As New List(Of Record)
recordList.Add(New Record(728, "Jim"))
recordList.Add(New Record(728, "Katie"))
recordList.Add(New Record(728, "Rich"))
recordList.Add(New Record(729, "John"))
recordList.Add(New Record(729, "Michael"))
Dim v = From r As Record In recordList
Group By ID = r.ID Into Records = Group
Select ID, Name = String.Join(","c, Records.Select(Function(x) x.Name))
End Sub
This should do what you want:
Dim result = list.GroupBy(Function(a) a.ID) _
.Select(Function(g) New With {.ID = g.Key, .csvList = g.Select(Function(n) n.Name) _
.Aggregate(Function(accumulation, current) accumulation + "," + current)}) _
.ToList()
This is an example using LINQ to Dataset:
Dim grouped =
From row In dt.AsEnumerable()
Group row By id = row.Field(Of Integer)("ID") Into Group
Select ID, Name = String.Join(",", From i In Group Select i.Field(Of String)("Name"))
pretty late but i also ran into same problem and this is my solution. Hope this helps someone
Dim grouped =
a.AsEnumerable().
GroupBy(Function(row) row.Field(Of Integer)("ID")).
Select(Function(group, ID)
Return New With
{
.ID= ID,
.Name= String.Join(",", group.Select(Function(row) row.Field(Of String)("Name")))
}
End Function)

Filter Data from dataset that is passed to textbox

I am iterating through columns in a datagridview in vb net and passing the
values to a textbox. I need to be able to filter out the emails which are in Cell(4), so that there are no duplicate emails for any single customer.
I have no idea of how to do this using a dataset.
EmailTableAdapter.Fill(Me.EmailDataset.Email)
Dim r As String = String.Empty
For i As Integer = 0 To Me.EmailDataGridView.RowCount - 1
r = r & EmailDataGridView.Rows(i).Cells(7).Value.ToString & " - " & EmailDataGridView.Rows(i).Cells(4).Value.ToString & vbNewLine
Next
TextBox2.Text = (r)
One way to filter out rows with duplicate values in Cells(4) would be to iterate through the grid rows, stuffing items into a Dictionary using Cells(4) values as the Key, and then iterate through the Dictionary to build your "r" string. Such a solution would look something like this:
EmailTableAdapter.Fill(Me.EmailDataset.Email)
Dim EmailDict As New Dictionary(Of String, String)
For i As Integer = 0 To Me.EmailDataGridView.RowCount - 1
If Not EmailDict.ContainsKey(EmailDataGridView.Rows(i).Cells(4).Value.ToString) Then
EmailDict.Add(EmailDataGridView.Rows(i).Cells(4).Value.ToString, EmailDataGridView.Rows(i).Cells(7).Value.ToString)
End If
Next
Dim EmailPair As KeyValuePair(Of String, String)
Dim r As String = String.Empty
For Each EmailPair In EmailDict
r &= EmailPair.Value & " - " & EmailPair.Key & vbNewLine
Next
TextBox2.Text = (r)

for loop for a string variable

this is my code -
for i as integer = 0 to rows.count - 1
output &= "Name =" & row(i)("Name")
output &= "lastName =" & row(i)("lastName")
... 50 more fields
next
i need the output to be like this
Applicant1Name = MikeApplicant1lastName = ditkaApplicant2Name = TomApplicant2lastName = Brady ...
how do i do this without putting the following code 50 times -
output &= "Applicant" & i.tostring() + 1 &"Name =" & row(i)("Name")
... and so on.
is there a way to make a for loop and run applicant 1,2,3,4.... in one shot?
thanks
Try:
Dim output as New StringBuilder("")
For i as Integer = 0 To rows.Count - 1
output.append("Applicant" + i.ToString())
Foreach(col as DataColumn in dt.Columns) ' The datatable where your rows are
Dim colName as string = col.ColumnName
output.append(colName & "=" & rows(i)(colName).ToString())
Next
If i < rows.Count - 1 Then output.Append("|")
Next
StringBuilder is faster for string concatenations, and if you keep your rows in a datatable (which I assume is happening because that's how it looks like you're accessing them), then you can just iterate through the columnnames at the top level.
You really cant as you are trying to append 50 different fields.
The only thing you can shorten is the variable name:
Dim strLN as String = row(i)("lastName")
Dim strFirstName as String = row(i)("firstName")
Then you simply put it all together
output &= strLN & strFirstName...etc
looks like you want to create an array of all the fields you have and then include a nested loop.
Dim fields As String() = {"Name", "LastName", "SSN", "Birthdate"}
Dim output As String = ""
For i As Integer = 1 To rows.count
For Each field As String In fields
output = String.Concat(output, "Applicant ", i, field, "=", row(i)(field), " ")
Next
Next