Joining StringBuilder - vb.net

I am a newbie
I have problem with string builder. I want to show to Richtextbox in vb with Richtextbox template
i.e.
Jan 674 Meet 670 Missed 4
Feb 635 Meet 631 Missed 4
etc.
with source from datagirdview with 8 columns and xxxx rows.
for ex. columns are : Registered Date, Deadline Date, Month, Meet/Not Meet,etc.
This my Code :
For Each keyvalue As KeyValuePair(Of String, Integer) In DicMonth
sb.AppendLine(String.Format("{0} : {1}", UCase(keyvalue.Key), keyvalue.Value))
Next
For Each keyvalue1 As KeyValuePair(Of String, Integer) In DicMeetTotal
sb.AppendLine(String.Format("{0}", "MEET : " & keyvalue1.Value))
Next
RichTextBox2.Text = sb.ToString
and the result is :
Jan : 674
Feb : 635
Mar : 623
Meet : 670
Meet : 631
Meet : 621
Missed : 4
Missed : 4
Missed : 2

Assuming the same order and length of dictionaries, you can use Zip to stitch the two dictionaries together:
Sub Main
Dim sb = New StringBuilder()
Dim DicMonth = New Dictionary(Of String, Integer)() From { _
{"Jan", 674}, _
{"Feb", 635} _
}
Dim DicMeetTotal = New Dictionary(Of String, Integer)() From { _
{"Jan", 670}, _
{"Feb", 631} _
}
Dim lineStrings = DicMonth.Zip(DicMeetTotal, _
Function(m, mt) String.Format("{0} {1} Meet {2} Missed {3}", _
m.Key, m.Value, mt.Value, m.Value - mt.Value))
For Each ls In lineStrings
sb.AppendLine(ls)
Next
Console.WriteLine(sb.ToString())
End Sub
Alternatively, if there is a join key (e.g. the Key value in both dictionaries is the same), you can use Linq Join them together, like so:
Dim lineStrings = DicMonth.Join(DicMeetTotal, _
Function(m) m.Key, Function(mt) mt.Key, _
Function(m, mt) String.Format("{0} {1} Meet {2} Missed {3}", _
m.Key, m.Value, mt.Value, m.Value - mt.Value))
Edit
Assuming that you wouldn't have modelled N different dictionaries each containing just a single value (this would be a modelling error along the lines of Entity Attribute Value, IMO), I'm guessing you'll want an entity to hold the data:
Class MeetTotalEntity
Public Property Meet As Integer
Public Property Missed As Integer
Public Property Cancel As Integer
Public Property Other As Integer
End Class
And then the Zip (or Join) still holds. The Value of the second dictionary contains the above entity, so just dereference the fields accordingly.
Sub Main
Dim sb = New StringBuilder()
Dim DicMonth = New Dictionary(Of String, Integer)() From { _
{"Jan", 674}, _
{"Feb", 635} _
}
Dim DicMeetTotal = New Dictionary(Of String, MeetTotalEntity)() From { _
{"Jan", New MeetTotalEntity With {.Meet = 670, .Missed = 4, .Cancel = 10, .Other = 5}}, _
{"Feb", New MeetTotalEntity With {.Meet = 631, .Missed = 10, .Cancel = 3, .Other = 2}} _
}
Dim lineStrings = DicMonth.Zip(DicMeetTotal, _
Function(m, mt) String.Format("{0} Total {1} Meet {2} Missed {3} Cancel {4} Other {5}", _
m.Key, m.Value, mt.Value.Meet, mt.Value.Missed, mt.Value.Cancel, mt.Value.Other))
For Each ls In lineStrings
sb.AppendLine(ls)
Next
Console.WriteLine(sb.ToString())
End Sub

Related

object Collection Containing a List of IDs Linq

I have a list box and the user is able to multi-select. I want to use Linq and bring back the records of the selected IDs that the user selects. I need to bring back the full object record for each selected ID
Here is the contact object along with collection object
Namespace MODEL
<System.Serializable()> _
Public Class ContactCollection
Inherits System.Collections.ObjectModel.Collection(Of Contact)
Implements IList(Of Contact)
End Class
End Namespace
Namespace MODEL
<System.Serializable()> _
Public Class Contact
Private mContactID As Int32 = 0
Private mFirstName As String
Private mLastName As String
Public Property ContactID As Int32
Get
Return mContactID
End Get
Set(value As Int32)
mContactID = value
End Set
End Property
Public Property FirstName As String
Get
Return mFirstName
End Get
Set(value As String)
mFirstName = value
End Set
End Property
Public Property LastName As String
Get
Return mLastName
End Get
Set(value As String)
mLastName = value
End Set
End Property
End Class
End Namespace
Adding 5 Records to the collection object
Dim objCollection As New MODEL.ContactCollection
Dim obj As New MODEL.Contact
objCollection.Add(New MODEL.Contact With {
.ContactID = 1, _
.FirstName = "John", _
.LastName = "Smtih" _
})
objCollection.Add(New MODEL.Contact With {
.ContactID = 2, _
.FirstName = "Mark", _
.LastName = "Davis" _
})
objCollection.Add(New MODEL.Contact With {
.ContactID = 3, _
.FirstName = "Tom", _
.LastName = "Howe" _
})
objCollection.Add(New MODEL.Contact With {
.ContactID = 4, _
.FirstName = "Jerry", _
.LastName = "Thomas" _
})
objCollection.Add(New MODEL.Contact With {
.ContactID = 5, _
.FirstName = "Jane", _
.LastName = "Marry" _
})
This is the selected contact List from the list box
Dim lstContacts As New List(Of Integer)
lstContacts.Add(2)
lstContacts.Add(4)
I am not sure what to do at this point with Linq to find the values. I think I have to use contains but I have tried may different ways but I was unable to get the values.
I have tried this Linq but does not work or bring any records back
Dim objSearch from SearchContacts in objCollection
Where (lstContacts.Contains(SearchContacts.ContactID))
To get the Ids, try that :
Dim ids As IEnumerable(Of Int32) = myListBox.SelectedItems _
.OfType(Of Contact)() _
.Select( Function(c) c.ContactID ) _
Edit
If you want the Contacts, you can just just :
Dim ids As IEnumerable(Of Contact) = myListBox.SelectedItems _
.OfType(Of Contact)()
And if you want the contacts in a separate copied collection, you can :
Dim ids As List(Of Contact) = myListBox.SelectedItems _
.OfType(Of Contact)() _
.ToList()
Last (if think this is your real question - just tell and I erase everything above)
Dim selectedContacts As IEnumerable(Of MODEL.Contact) = From contact In objCollection
Join id In lstContacts
On contact.ContactID Equals id
Select contact

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

'Order by' ignored in LINQ query

I am trying to sort a list by company name. I have tried the following code but this sorts the list by CompID and not CoShort. How should I change this to sort by CoShort?
Public Shared Function [SelectCompanyData](iElement() As Integer) As List(Of CompanyList)
Dim db As New EntryDataContext()
Dim q As IQueryable(Of CompanyList) = (From Act_Sub_Manfu_Link In db.Act_Sub_Manfu_Links _
Join Company In db.Companies _
On Act_Sub_Manfu_Link.CompID Equals Company.CompID _
Where iElement.Contains(Act_Sub_Manfu_Link.ACCN) _
And Company.In_Dir _
Select New CompanyList With { _
.CompID = Company.CompID, _
.InDir = Company.In_Dir, _
.CoShort = Company.CoShort _
}).Distinct
q.OrderBy(Function(c) c.CoShort)
Dim list As List(Of CompanyList) = q.ToList
Return list
End Function
You have to assign ordered collection into a variable:
Dim oq As IOrderedQueryable(Of CompanyList) = q.OrderBy(Function(c) c.CoShort)
And use it to get List of results:
Dim list As List(Of CompanyList) = oq.ToList()
Doesn't need to be assigned to anything but the return value
Public Function SelectCompanyData(iElement() As Integer) As List(Of CompanyList)
Dim db As New EntryDataContext()
Return (From Act_Sub_Manfu_Link In db.Act_Sub_Manfu_Links _
Join Company In db.Companies _
On Act_Sub_Manfu_Link.CompID Equals Company.CompID _
Where iElement.Contains(Act_Sub_Manfu_Link.ACCN) _
And Company.In_Dir _
Select New CompanyList With { _
.CompID = Company.CompID, _
.InDir = Company.In_Dir, _
.CoShort = Company.CoShort _
}).Distinct().OrderBy(Function(c) c.CoShort).ToList()
End Function

Remove last element from array

How to remove the last element from an array in VB.NET. I need to split the street and housenumber.
STREET
Split the address on spaces
Remove last element (missing in the code)
Join array
NUMBER
Split the address on spaces
get last element
My code:
'split address
Dim addressArray() As String = args.Content.Split(" ")
'remove last element and return the joined array
Return String.Join(" ", addressArray.Remove(addressArray.Length() - 1))
Dim foo() As String = "This is a test".Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries)
Array.Resize(foo, foo.Length - 1)
Dim s As String = String.Join(" ", foo)
or use lists
Dim foo As New List(Of String)
foo.AddRange("This is a test".Split(New Char() {" "c}, StringSplitOptions.RemoveEmptyEntries))
foo.RemoveAt(foo.Count - 1)
Dim s As String = String.Join(" ", foo)
As far as using LINQ and performance, judge for yourself
Public Class Form1
'to LINQ or not to LINQ
'judge for yourself
Dim stpw As New Stopwatch
Private Sub Button1_Click(sender As System.Object, _
e As System.EventArgs) Handles Button1.Click
Dim ipsumA() As String = New String() {"Lorem", "ipsum", "dolor", "sit", _
"amet", "consectetur", "adipisicing", _
"elit", "sed", "do", "eiusmod", _
"tempor", "incididunt", "ut", "labore", _
"et", "dolore", "magna", "aliqua", "Ut", _
"enim", "ad", "minim", "veniam", "quis", _
"nostrud", "exercitation", "ullamco", _
"laboris", "nisi", "ut", "aliquip", "ex", _
"ea", "commodo", "consequat", "Duis", "aute", _
"irure", "dolor", "in", "reprehenderit", "in", _
"voluptate", "velit", "esse", "cillum", "dolore", _
"eu", "fugiat", "nulla", "pariatur", "Excepteur", _
"sint", "occaecat", "cupidatat", "non", "proident", _
"sunt", "in", "culpa", "qui", "officia", "deserunt", _
"mollit", "anim", "id", "est", "laborum"}
Const tries As Integer = 100000
Debug.WriteLine("")
stpw.Reset()
stpw.Start()
For x As Integer = 1 To tries
Dim s As String = arrayTake(ipsumA)
Next
stpw.Stop()
Debug.WriteLine(stpw.ElapsedTicks.ToString)
stpw.Reset()
stpw.Start()
For x As Integer = 1 To tries
Dim s As String = arrayRsz(ipsumA)
Next
stpw.Stop()
Debug.WriteLine(stpw.ElapsedTicks.ToString)
End Sub
Private Function arrayRsz(test As String()) As String
Array.Resize(test, test.Length - 1)
Return String.Join(" ", test)
End Function
Private Function arrayTake(test As String()) As String
Return String.Join(" ", test.Take(test.Length - 1))
End Function
End Class
You can't remove items from an array. The size of an array is decided when you create it, and can't be changed.
You can create a result that contains the items from the array except the last one:
Return String.Join(" ", addressArray.Take(addressArray.Length() - 1))
Edit:
If you are concerned about performance, you should not do any Split or Join at all, but simply get the parts of the string using simple string operations:
Dim pos As Integer = args.Content.LastIndexOf(" "C)
Dim street As String = args.Content.Substring(0, pos)
Dim number As String = args.Content.Substring(pos + 1)
This is at least ten times faster than any other method presented here.
Edit 2:
Here is the performance test code (C#):
Dim time As Performance = New Performance(1000000, 6)
Dim address As String = "aölskdjf öawe öofij 42"
Console.WriteLine(time.Take("SplitTakeJoin", Sub()
Dim parts As String() = address.Split(" "c)
Dim street As String = String.Join(" ", parts.Take(parts.Length - 1))
End Sub))
Console.WriteLine(time.Take("SplitResizeJoin", Sub()
Dim parts As String() = address.Split(" "c)
Array.Resize(parts, parts.Length - 1)
Dim street As String = String.Join(" ", parts)
End Sub))
Console.WriteLine(time.Take("Substring", Sub()
Dim street As String = address.Substring(0, address.LastIndexOf(" "c))
End Sub))
Output:
SplitTakeJoin 0,000511 ms.
SplitResizeJoin 0,000323 ms.
Substring 0,000031 ms.
using this performance test class:
Public Class Performance
Private _iterations As Integer
Private _displayDigits As Integer
Private _emptyTime As TimeSpan
Public Sub New(ByVal iterations As Integer, ByVal displayDigits As Integer)
_iterations = iterations
_displayDigits = displayDigits
_emptyTime = TimeSpan.Zero
_emptyTime = Take(Sub()
End Sub)
End Sub
Private Function Take(ByVal action As Action) As TimeSpan
Dim w As Stopwatch = Stopwatch.StartNew()
For i As Integer = 0 To _iterations - 1 Step 10
Action()
Action()
Action()
Action()
Action()
Action()
Action()
Action()
Action()
Action()
Next
w.Stop()
Return w.Elapsed - _emptyTime
End Function
Public Function Take(ByVal title As String, ByVal action As Action) As String
Dim Time As TimeSpan = Take(action)
Return title + " " + (Time.TotalMilliseconds / Convert.ToDouble(_iterations)).ToString("N" + _displayDigits.ToString()) + " ms."
End Function
End Class
You could also try using Redim Preserve. These statements are carry overs from the Visual Basic 6.0 days and are not considered the .NET way of doing things, but it is another option. There may be performance issues though according to this article.
Redim Preserve addressArray(addressArray.Length - 1)
Actually to delete the last item of array you would have to:
Redim Preserve addressArray(addressArray.Length - 2)
since they are zero based and the length is one based.
This will return all but the last "word/number" in a String as an array of Strings.
Return args.content.Split(" ").Take((args.content.Split(" ").Count - 1)).ToArray()

Linq to objects

I have 2 databases from different servers. I cannot link the databases. The data is retrieved from the databases as :
DB1
- Client_ID Engagement_ID Enabled Description
600 10 True Company1
600 20 False Company2
700 10 True Company3
DB2
Client_ID Engagement_ID Enabled
Description
600 5 True Company1
600 10 False Company2
500 30 True Company3
The T SQL for this task is:
select * from DB1
left join DB2 on DB1.client_ID = DB2.client_ID
and DB1.Engagement_ID = DB2.Engagement_ID
where DB2.CLient_ID is null
and DB2.Engagement_ID is null and DB1.client_id in (select client_id from DB2)
I need to do this VB.NET LINQ
The sample data you provided won't return any values anyway since they ClientId and EngagementId all have values.
I split the LINQ into two lists. I have yet to test this out or optimize it, but maybe this is what you're looking for to at least get you started.
Here is my attempt:
Public Class DBObject
Public Sub New(ByVal cId As Integer, _
ByVal eId As Integer, _
ByVal enabled As Boolean, _
ByRef desc As String)
_clientId = cId
_engagementId = eId
_enabled = enabled
_description = desc
End Sub
Private _clientId As Integer
Public Property ClientId() As Integer
Get
Return _clientId
End Get
Set(ByVal value As Integer)
_clientId = value
End Set
End Property
Private _engagementId As Integer
Public Property EngagementId() As Integer
Get
Return _engagementId
End Get
Set(ByVal value As Integer)
_engagementId = value
End Set
End Property
Private _enabled As Boolean
Public Property Enabled() As Boolean
Get
Return _enabled
End Get
Set(ByVal value As Boolean)
_enabled = value
End Set
End Property
Private _description As String
Public Property Description() As String
Get
Return _description
End Get
Set(ByVal value As String)
_description = value
End Set
End Property
End Class
Dim DB1 As New List(Of DBObject)
Dim DB2 As New List(Of DBObject)
DB1.Add(New DBObject(600, 10, True, "Company1"))
DB1.Add(New DBObject(600, 20, False, "Company2"))
DB1.Add(New DBObject(700, 10, True, "Company3"))
DB2.Add(New DBObject(600, 5, True, "Company1"))
DB2.Add(New DBObject(600, 10, False, "Company2"))
DB2.Add(New DBObject(500, 30, True, "Company3"))
Dim list1 As List(Of DBObject) = (From obj1 As DBObject In DB1 _
Join obj2 As DBObject In DB2 _
On obj1.ClientId Equals obj2.ClientId _
And obj1.EngagementId Equals obj2.EngagementId _
Where obj2.ClientId = Nothing _
And obj2.EngagementId = Nothing _
Select obj1).ToList
Dim list2 As List(Of DBObject) = (From obj3 As DBObject In list1 _
From obj4 As DBObject In DB2 _
Where obj3.ClientId = obj4.ClientId _
Select obj3).ToList
' list2 would have the results you desire
Dim list1 = From obj1 As DBObject In DB1 _
Group Join obj2 As DBObject In DB2 _
On obj1.ClientId Equals obj2.ClientId _
And obj1.EngagementId Equals obj2.EngagementId _
Into g = Group _
From r In g.DefaultIfEmpty() _
Where g.ElementAtOrDefault(0) Is Nothing _
Select New With {.Cl_ID = obj1.ClientId, .EngID = bj1.EngagementId}
Dim list2 = (From obj3 In list1 _
From obj4 In DB2 _
Where obj3.Cl_ID = obj4.ClientId _
Select obj3).Distinct.DefaultIfEmpty
I modified sunpech's code and List2 contains the expected result i.e. the second row of DB1 - 600, 20, False, "Company2"