Best Way to Read Lisbox Array - sql

I am using a sql query to retrieve data and write to a listbox. However, sometimes an item may have more than one value.
IE:
Data: "Patient Disclosure"
Value: "Encounter"
or
Data: "Patient Disclosure"
Value: "Order"
In the listbox, the line item will show only "Patient Disclosure" but I have the values written in the array. However, I don't want two of the same line item to appear. The "order" value should be the only one showing if it has multiple values. How can I do this?
While reader.Read()
Dim Myitem As New List(Of myitems)
Myitem.Add(New myitems with {.Description = reader(0), .Value = reader(2)})
' If reader(2) = "Order" Then
' listBox1.Items.Add(Myitem.ToArray)
' Else
' listBox1.Items.Add(reader(0))
' End If
listBox1.Items.AddRange(Myitem.ToArray)
End While

You can eliminate duplicates with
listBox1.Items.AddRange(Myitem.Distinct().ToArray())
However, I am not sure what you are asking. I good thing to do is to create a class that holds your data, instead of working directly with data readers, as you have done already. Give it a more descriptive name than myitems. As developers we are constantly working with many kinds of "items".
Public Class Patient // Or whatever the items are supposed to represent.
Public Property Description As String
Public Property Value As String
Public Overrides Function ToString() As String
Return String.Format("Description = {0}, Value = {1}", Description, Value)
End Function
End Class
If you then add Patient objects to a ListBox, the ListBox will automatically use ToString to display the items.
You can also override Equals and GetHashCode in order to influence the way two objects are compared. The Distinct method will use these two methods in order to do its job. See: Implementing the Equals Method

Related

VB: how to compare two objects to find out if the values of their properties are the same?

I have an object called Statistics. Inside this object there are 6 more objects. Each contains properties with values.
So for example, Statistics(0) contains an 'age' field, a 'sex' field, 'vehicle' etc...
same goes for Statistics(1), Statistics(2) etc...
What I want to do is compare Statistics(0) all the way to Statistics(6) and find out if any one of them is identical to another.
If all of the fields contained within Statistics(0) have the same values as the fields in Statistics(1), I want to do something.
How can I compare these objects to one-another?
what I have tried
For Each Stat As ExportStatistics In Statistics
Insert_VehicleStats(Stat) 'Insert values into main Vehicle table
If Statistics.Length > 1 Then
Dim i = 0
Dim y = 0
Dim previousObject As ExportStatistics
For Each Stat2 In Statistics
If Stat2.Equals(previousObject) Then
Dim sadXml = "do something"
End If
previousObject = Stat2
Next
End if
You can either override the Equals function in your class or overload it then create your own comparison code. Here's an example (it assumes your object is of type VehicleStatisticsItem):
Public Class VehicleStatisticsItem
Public Overrides Function Equals(obj As Object) As Boolean
'Test for type and define tests or just pass to base function
Return MyBase.Equals(obj)
End Function
Public Overloads Function Equals(item As VehicleStatisticsItem) As Boolean
'Define your tests here
End Function
End Class
The 2 objects you are comparing will not equal each other even if their properties do. You need to specify that you are comparing their properties.
Change
If vehicleStatistic.Equals(previousObject) Then
Dim sadXml = "do something"
End If
To
If vehicleStatistic.GetType().GetProperties.Equals(previousObject.GetType().GetProperties) Then
Dim sadXml = "do something"
End If
This way you are comparing their properties.

Combining two list, only records with 1 specific unique property

I'm combining two lists in visual basic. These lists are of a custom object. The only record I want to combine, are the once with a property doesn't match with any other object in the list so far. I've got it running. However, the first list is just 1.247 records. The second list however, is just short of 27.000.000 records. The last time I successfully merged the two list with this restriction, it took over 5 hours.
Usually I code in C#. I've had a similar problem there once, and solved it with the any function. It worked perfectly and really fast. So as you can see in the code, I tried that here too. However it takes way too long.
Private Function combineLists(list As List(Of Record), childrenlist As List(Of Record)) As List(Of Record) 'list is about 1.250 entries, childrenlist about 27.000.000
For Each r As Record In childrenlist
Dim dublicate As Boolean = list.Any(Function(record) record.materiaalnummerInfo = r.materiaalnummerInfo)
If Not dublicate Then
list.Add(r)
End If
Next
Return list
End Function
The object Record looks like this ( I wasn't sure how to make a custom object in VB, and this looks bad, but it worked):
Public Class Record
Dim materiaalnummer As String
Dim type As String 'Config or prefered
Dim materiaalstatus As String
Dim children As New List(Of String)
Public Property materiaalnummerInfo()
Get
Return materiaalnummer
End Get
Set(value)
materiaalnummer = value
End Set
End Property
Public Property typeInfo()
Get
Return type
End Get
Set(value)
type = value
End Set
End Property
Public Property materiaalstatusInfo()
Get
Return materiaalstatus
End Get
Set(value)
materiaalstatus = value
End Set
End Property
Public Property childrenInfo()
Get
Return children
End Get
Set(value)
children = value
End Set
End Property
End Class
I was hoping that someone could point me in the right direction to shorten the time needed. Thank you in advance.
I'm not 100% sure what you want the output to be such as all differences or just ones from the larger list etc but I would definitely try do it with LINQ! Basically sql for vb.net data so would something similar to this:
Dim differenceQuery = list.Except(childrenlist)
Console.WriteLine("The following lines are in list but not childrenlist")
' Execute the query.
For Each name As String In differenceQuery
Console.WriteLine(name)
Next
Also side-note i would suggest not calling one of the lists "list" as it is bad practice and is a in use name on the vb.net system
EDIT
Please try this then let me know what results come back.
Private Function combineLists(list As List(Of Record), childrenlist As List(Of Record)) As List(Of Record) 'list is about 1.250 entries, childrenlist about 27.000.000
list.AddRange(childrenlist) 'combines both lists
Dim result = From v In list Select v.materiaalnummerInfo Distinct.ToList
'result hopefully may be a list with all distinct values.
End Function
Or Don't combine them if you dont want to.

Combo Box items - Display Member for List(Of String)?

My project is in Visual Basic. I am trying to create a custom & savable "filter" for a DataGridView using several TextBoxes. Right now, any List(Of String) that is added to the Combo Box is displayed in the box as (Collection). I want my users to be able to select the one they created, so I would like the Lists to have a display name that can be selected in the Combo Box. Here is some of the code.
Dim savedFilter As New List(Of String)
savedFilter.Add(NameTextBox.Text)
savedFilter.Add(AgeTextBox.Text)
savedFilter.Add(NotesTextBox.Text)
ComboBoxSavedFilters.Items.Add(savedFilter)
Is it possible to add a display name for a List?
Or if you are lazy use buid-in generic class Tuple From MSDN.
Create collection of Tuple(Of String, List(Of String)) and use approach suggested by #Plutonix for binding collection to ComboBox
Dim savedFilter As New List(Of Tuple(Of String, List(Of String)))()
savedFilter.Add(
Tuple.Create("default",
New List From {"filter1", "filter2", "filter3"}))
savedFilter.Add(
Tuple.Create("Blue ones",
New List From {"filter4", "filter5"}))
savedFilter.Add(
Tuple.Create("Old ones",
New List From {NameTextBox.Text, AgeTextBox.Text, NotesTextBox.Text}))
With ComboBoxSavedFilters
.DisplayMember = "Item1" 'Name of first property in Tuple type
.ValueMember = "Item2" 'Name of second property in Tuple type -List
.DataSource = savedFilter
End With
Then SelectedValue will contain currently selected filter's collection,
which can be accessed like that
Dim filter As List(Of String) =
DirectCast(Me.ComboBoxSavedFilters.SelectedValue, List(Of String))
You could setup under My.Settings a StriingCollection
Initializing (you can omit the items added if so desired)
If My.Settings.Filters Is Nothing Then
My.Settings.Filters = New StringCollection() From {"One", "Two"}
End If
Setup items in a ComboBox
ComboBox1.Items.AddRange(My.Settings.Filters.Cast(Of String).ToArray)
Adding an item
My.Settings.Filters.Add(Now.ToShortDateString)
You can remove and clear items too.
Provide a Display Member for List(Of String)
Apparently, these are less a collection of filters than a collection of criteria or clauses for one Filter:
I condensed the code in the question, but there are 14 fields that can be filtered and there are multiple filters that can be applied on one field.
For the multiples per field, I am not sure I would want to store those individually, but keep the field criteria together. So, if you want to apply a name to these, a class would not only do that but could help manage the filter elements:
Public Class SuperFilter
Public Property Name As String
Public Property Elements As SortedList
Public ReadOnly Property FilterText As String
Get
Return GetFilterText()
End Get
End Property
Public Sub New(n As String)
Name = n
Elements = New SortedList
End Sub
Public Sub AddItem(filter As String)
Elements.Add(Elements.Count, filter)
End Sub
Public Sub InsetAt(index As Int32, filter As String)
Elements.Add(index, filter)
End Sub
Private Function GetFilterText() As String
Dim els(Elements.Count - 1) As String
Elements.Values.CopyTo(els, 0)
Return String.Join(" ", els)
End Function
Public Overrides Function ToString() As String
Return String.Format("{0} ({1})", Name, Elements.Count.ToString)
End Function
End Class
You would need to add methods and properties like Remove and Count but this should be enough to demonstrate. I am not sure about the SortedList, a Dictionary using the field name might be better, but something to control the order seems worthwhile. I am also unsure I would expose the Elements collection - managing it might be better left to the class.
Hopefully, the Combo displaying a set of these (as opposed to the filter elements/clauses) is the goal.
Private filters As New List(Of SuperFilter)
Add filter items to the list:
Dim item As New SuperFilter("Default")
item.AddItem("Id = 7")
filters.Add(item)
item = New SuperFilter("Blue Ones")
item.AddItem("Color = Blue")
filters.Add(item)
item = New SuperFilter("Complex")
item.AddItem("[Name] like %Bob% OR [Name] like %Alice%")
item.AddItem("AND Color = 'Blue'")
item.AddItem("AND Active=True")
item.AddItem("AND AccessRequired < 3")
item.AddItem("AND DateAdded > #2/11/2010#")
item.AddItem("AND CreatedBy = 'ziggy'")
filters.Add(item)
cbo1.DataSource = filters
cbo1.DisplayMember = "Name"
cbo1.ValueMember = "FilterText"
The value member could be the Elements - the collection of filter clauses, or it could be the query text. The GetFilterText method joins them together for you as part of what a filter manager class could/should:
For n As Int32 = 0 To filters.Count - 1
Console.WriteLine("Name: {0} Count: {1}{2}Text:{3}", filters(n).Name,
filters(n).Elements.Count,
Environment.NewLine, filters(n).FilterText)
Next
Result:
Name: Default Count: 1
Text:Id = 7
Name: Blue Ones Count: 1
Text:Color = Blue
Name: Complex Count: 6
Text:[Name] like %Bob% OR [Name] like %Alice% AND Color = 'Blue' AND Active=True AND AccessRequired < 3 AND DateAdded > #2/11/2010# AND CreatedBy = 'ziggy'
If you use "Elements" as the ValueMember you will get back the collection.
The combo displays the Name for the user. On the right, a label displays the ValueMember in this case, it is the FilterText or joined Elements. As I said, you could get back the actual collection as the SelectedValue instead, but that is available as part of SelectedItem.
If savable means beyond the life of the application instance, that is another question, but these are very easily serialized.

vb- sort list of class by sortexpression

I have a class that contains a lot of fields.
I want to order the list of items of my class by one property, then by the other and so on...
I need to do that using SortExpression and SortDirection.
How can I do this in vb?
Dim LsDocuments As List (Of clsDoc) = GetDocuments()
clsDoc is a class with properties:
Date
Hour
Key
Office
I need something like: LsDocuments.orderby("Date","Asc"), and not like LsDocuments.orderby(Functuion(x) x.Date) because it's not general- every time I need to sort by other property (and doing Select case is very not classic).
What I often do is create a property that contains all the values as a string and then sort by that property. Just make sure your string is sortable by making it fixed width. For example:
Public Readonly Property Sort1 as string
Get
Return Date.Tostring("s") & Hour.Tostring.PadLeft(2,"0") & Key.PadRight(50," ") & Office.PadRight(50," ")
End Get
End Property

Possible to add some sort of identification onto list items?

I'm just curious if it's possible to gather a list of data and put it into a list or array and easily pull them out using some variable(like a tag property on controls) on each item in the list rather than using the index. An example would be if i have many controls on a form and would like to populate the values using the list but instead of having to cross check a lot of different indicies(would take a lot of time) i could just assign the label to some 'tag like' variable for the list item.
Is this possible?
Lists in .NET, such as the List(Of T) class, only support storing one object per item. However, the beauty of them is, you can store any type of object that you want. If you need to store metadata with your data, simply create a new class that holds all the data for each item. For instance:
Public Class MyControlData
Public Property LabelText As String
Public Property Value As String
End Class
Then you can add the items to the list like this:
Dim dataList As New List(Of MyControlData)()
Dim item As New MyControlData()
item.LabelText = "Name"
item.Value = "Bob"
dataList.Add(item)
And you can read the data from the list like this:
For Each i As MyControlData in dataList
Label1.Text = i.LabelText
TextBox1.Text = i.Value
Next
I would use a Dictionary object so you can use a key to reference your data easily.
You can use LINQ:
Dim myTagControls = From ctrl In Me.Controls.Cast(Of Control)()
Where "your-tag".Equals(ctrl.Tag)
For Each ctrl In myTagControls
Console.WriteLine("Tag:{0} Name:{1}", ctrl.Tag, ctrl.Name)
Next