Checking to see if name is already in list - vb.net

I have a dialog box which asks for details of a customer, they are saved as a list
Private fNames As List(Of String)
I have a method which checks to see if the name is in the list and returns true if they are and false if they are not.
Public Function isNameInList(ByVal myName As String) As Boolean
Return fNames.Contains(myName)
End Function
If the returned value is false the name is added.
Public Sub addName(ByVal myName As String)
If isNameInList(myName) = False Then
fNames.Add(myName)
End If
End Sub
The name is added to the list and is further displayed in a list box. I go to add the same name and it again is added to the list box when it shouldn't be. Have I missed something?

Rather than use a List you probably want to use a Set such as a HashSet.
Sets by definition do not allow duplicates and are very similar in use to Lists. If a set already contains a value, Add will return false and the value will simply not be added. If it is still added, then the values are not exactly identical (as defined by the Equals and GetHashCode methods).
Note: Equals for Strings is case and white-space sensitive, so you will probably need to Trim the String and convert to one case or use StringComparer.OrdinalIgnoreCase when comparing.
myString.Trim().Equals(myOtherString.Trim(), StringComparer.OrdinalIgnoreCase)
If you wish to do more work, you can even write your own StringComparer.

The comparision is case sensitive. This means that "Joe" and "joe" are different and will both be added. Could this be your problem?
I have tested your code. It seems to work. However you are also talking about a list box. Are you doing something wrong there?
If you declare your list as System.ComponentModel.BindingList(Of String) instead of List(Of String) and then assign this list to the listbox like this:
ListBox1.DataSource = fNames
then the new names will automatically be displayed in the ListBox when you add them to fNames.

Related

ArrayList.Contains Always Returns False (Checking for an Object)

I'm trying to utilize an ArrayList in VBA (though it's the same ArrayList as available in C# and VB.net). When checking if an object is in the array list, the output is always false.
Example checking if "anotherPart" already exists in "partsList". Here it should already exist, because an identical "testPart" has already been added:
Dim partsList As Object
Set partsList = CreateObject("System.Collections.ArrayList")
Dim testPart As New part
testPart.Number = "10"
partsList.Add testPart
Dim anotherPart As New part
anotherPart.Number = "10"
Debug.Print ("partsList contains: " & partsList.Contains(anotherPart))
Debug output:
partsList contains: False
Why won't partsList.Contains(anotherPart) return true???
testPart and anotherPart are different parts, but they are identical, being defined with number="10".
partsList.Contains(testPart) returns true, but I don't understand why partsList.Contains(anotherPart) returns false if anotherPart is the same as testPart?
Edit to clarify purpose:
The reason I'm asking this, is I want to check if anotherPart already exists in the list, and only add it if an identical entry is not present. I'd expected to be able to do this, but can't because contains always returns false, and I end up adding tons of duplicate parts:
If Not partList.Contains(anotherPart) Then
partsList.Add anotherPart
End If
This seemed to show this as being possible, though they are overwriting the same udtPerson each time. Is there not a way to check this if using a "new" part and not overwriting an existing part? If I'm comparing one list against another for example each object will have been a "new" one.
http://www.java2s.com/Tutorial/VB/0160__Collections/UseArrayListContainstocheckifaobjectalreadyexists.htm

VB.NET Argument Prompt cannot be converted to type string

I'm made a new list of string and when I try to add something there it gives me an error: Argument 'Prompt' cannot be converted to type 'string
My code:
Dim variables As New List(Of String)
Try
variables.Append(CStr(TextBox1.Text))
variables.Append(CStr(TextBox2.Text))
MsgBox(variables)
Catch ex As Exception
MsgBox(ex.Message)
End Try
How can I fix that?
The error is coming from your use of MsgBox(). You're passing it the variables variable, and it doesn't know how to convert a List(Of String) to a String.
As stated by jmcilhinney, you should be using Add() instead of Append().
Additionally, you should use MessageBox.Show() instead of MsgBox().
As for the error, we can only assume you want to see all the current values in your List? If so, one solution is to use String.Join() and display that instead:
Dim variables As New List(Of String)
variables.Add(TextBox1.Text)
variables.Add(TextBox2.Text)
MessageBox.Show(String.Join(",", variables))
But your variables list should be declared at Form level so that you aren't creating a new one each time. It isn't clear from your post if this is the case or not.
You should be calling the Add instance method of your List(Of String). Append is an extension method and is not appropriate in that scenario. Append would be used for an enumerable list that you wanted to enumerate on the spot, e.g.
Dim names = {"Peter", "Paul", "Mary"}
Dim pNames = names.Where(Function(name) name.StartsWith("P"))
For Each pName In pNames.Append("Philip")
Console.WriteLine(pName)
Next
In that case the Append only affects the list being enumerated by the loop where it's used. The original list is unaffected.
You should be using the Add method:
Dim variables As List(Of String) = New List(Of String)
variables.Add(TextBox1.Text)
(No need for the redundant CStr as TextBox1.Text is already of type String.)
As #Mary will no doubt suggest - rightly! - always have Option Explicit and Option Strict set to On (and in my opinion Option Infer Off); it'll help you with any syntax issues.
And always pay attention to the syntax/compiler suggestions in the left margin which will give you clues/tips to fix or improve your code.
Lastly, refer to the Microsoft documentation if in doubt. It should be your first port-of-call if you're unsure of anything.
As several people have mentioned, use the .Add method not .Append.
The .Text property of a TextBox is already a String. No need to convert with CStr().
A message box displays a String. variables is not a String; it is a List(Of String). To see what is in your list use a For Each loop.
Private Sub OpCode()
Dim variables As New List(Of String)
variables.Add(TextBox1.Text)
variables.Add(TextBox2.Text)
For Each s In variables
MsgBox(s)
Next
End Sub
#SteveCinq is correct :-); turn on Option Strict.

How to get specific index of a Dictionary?

I'm working on a code that returns a query result like MySqlCommand, all working well but what I'm trying to do is insert the result inside a ComboBox. The way for achieve this is the following:
Form load event execute the GetAvailableCategories function
The function executed download all the values and insert it into a dictionary
Now the dictionary returned need an iteration for each Items to insert in the ComboBox
Practice example:
1,3. Event that fire the function
Private Sub Service_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each categoria In Categories.GetAvailableCategories()
service_category.Items.Add(categoria)
Next
End Sub
GetAvailableCategories function
Dim dic As New Dictionary(Of Integer, String)
For Each row In table.Rows
dic.Add(row(0), row(1))
Next
Return dic
How you can see in the 1,3 points I call the function that return the result. What I want to do is insert the row(0) as value of the item and row(1) as Item name. But Actually I get this result in the ComboBox:
[1, Hair cut]
and also I can't access to a specific position of the current item in the iteration. Maybe the dictionary isn't a good choice for this operation?
Sorry if the question could be stupid, but it's a long time since I don't program in vb.net and now I need to brush up a bit.
UPDATE
I've understood that I can assign the value access to the .key of my dictionary, so the result that I want achieve is correct if I do:
cateogoria.key (return the id of record taken from the db)
categoria.value (is the item name that'll display in the ComboBox)
now the problem's that: How to assign the value of the current item without create any other new class? For example:
service_category.Items.Add(categoria.key, categoria.value)
But I can't do this, any idea?
A List as a DataSource sounds like what you are really after. Relying on relative indices in different arrays is sort of flaky. There is not a lot about what these are, but a class would keep the related info together:
Public Class Service
Public Property Name As String
Public Property Category As String
Public Property Id As Int32
End Class
This will keep the different bits of information together. Use them to store the info read from the db and use a List to store all of them:\
Private Services As New List(of Service)
...
For Each row In table.Rows
Dim s As New Service
s.Name = row(0).ToString() '???
s.Category =...
s.Id = ...
Services.Add(s) ' add this item to list
Next
Finally, bind the List to the CBO:
myCbo.DataSource = Services
myCbo.DisplayMember = "Name" ' what to show in cbo
myCbo.ValueMember = "Id" ' what to use for SelectedValue
I dont really know what you want to show or what the db fields read are, so I am guessing. But the larger point is that a Class will keep the different bits of info together better than an array. The List can be the DataSource so that you dont even have to populate the CBO directly. The List can also be Sorted, searched, Filtered and so forth with linq.
When the user picks something, myCbo.SelectedItem should be that item (though it will need to be cast), or you can use SelectedIndex to find it in the list:
thisOne = Services(myCbo.SelectedIndex)
It is also usually a good idea to override ToString in the item/service class. This will determine what shows when a DisplayMember mapping is not available. Without this, WindowsApp2.Service might show for your items:
Public Overrides ToString() As String
Return String.Format("{0} ({1})", Name, Price)
End Sub
This would show something like
Haircut ($12.30)

VB.NET - Find a Substring in an ArrayList, StringCollection or List(Of String)

I've got some code that creates a list of AD groups that the user is a member of, with the intention of saying 'if user is a member of GroupX then allow admin access, if not allow basic access'.
I was using a StringCollection to store this list of Groups, and intended to use the Contains method to test for membership of my admin group, but the problem is that this method only compares the full string - but my AD groups values are formatted as cn=GroupX, etc....
I want to be easily able to determine if a particular substring (i.e. 'GroupX') appears in the list of groups. I could always iterate through the groups check each for a substring representing my AD group name, but I'm more interested in finding out if there is a 'better' way.
Clearly there are a number of repositories for the list of Groups, and it appears that Generics (List(Of String)) are more commonly preferred (which I may well implement anyway) but there is no in-built means of checking for a substring using this method either.
Any suggestions? Or should I just iterated through the list of groups?
RESULT:
I've settled on using a List(Of), and I've borrowed from Dan's code to iterate through the list.
I don't think you're going to find a better method than enumerating over the collection*.
That said, here's a good way to do it that will be independent of collection type:
Public Function ContainsSubstring(ByVal objects As IEnumerable, ByVal substring As String) As Boolean
Dim strings = objects.OfType(Of String)()
For Each str As String in strings
If str.Contains(substring) Then Return True
Next
Return False
End Function
This is a good way to address the "which collection to use?" issue since basically all collections, generic or not (ArrayList, List(Of String), etc.), implement IEnumerable.
*Justification for why I believe this forthcoming.
Writing a helper function which will iterate through the items checking for substrings and returning you a Boolean flag seem to be your best bet.
You can use a predicate function for that. It's a boolean function which will help you to filter out some entries.
For example, to get non-hidden files from a list:
Public ReadOnly Property NotHiddenFiles As List(Of FileInfo)
Get
Dim filesDirInfo As New DirectoryInfo(FileStorageDirectory)
Return filesDirInfo.GetFiles.ToList.FindAll(AddressOf NotHiddenPredicate)
End Get
End Property
Private Function NotHiddenPredicate(ByVal f As FileInfo) As Boolean
Return Not ((f.Attributes And FileAttributes.Hidden) = FileAttributes.Hidden)
End Function

Listbox Control Item - Multiple Names (and/or variables)?

I have a lot of data that's coming from a database and being adding to a listbox. The data that's coming from the database is a unique ID, and a name.
Is there any way I can make the item contain both the ID and name? I know I can append it, that's not what I'm looking to do. I need a way to be able to either get the ID, or get the name, while displaying them both.
I have gotten as far as creating a class:
Class Item
Property ID as Integer
Property Name as String
Sub New(ID as Integer, Name as String)
Me.ID = ID
Me.Name = Name
End Sub
Overrides Function ToString() as String
Return Name
End Function
End Class
That looks like it should do the trick, but I'm having trouble getting the ID, instead of the name. To put it simply, I wish I could do this: listbox1.selecteditem(id) to get the id, or listbox1.selecteditem(name) to get the name.
Any ideas on how to implement this?
You can bind to a List(Of Item) like this:
Dim ItemList = New List(Of Item)
' Fill the list with appropiate values.'
listbox1.DataSource = ItemList
listbox1.DisplayMember = "Name"
listbox1.ValueMember = "ID"
Then listbox1.SelectedValue holds the ID and you can access the name like this:
DirectCast(listbox1.SelectedItem, Item).Name
If you want to show both the ID and the Name, then I suggest you add a property to be the displayed value in the Itemclass:
Public ReadOnly Property DisplayedValue() as String
Get
Return Me.Name & " (" & Me.ID.ToString & ")"
End Get
End Property
Then when binding the list make
listbox1.DisplayMember = "DisplayedValue"
Update:
Based on your comments below I'd say my solution still works. However with this methodology the items must be added to the list and then the list bound to the object. The items can not be added individually and directly to the list box (as you would be separating data from presentation I don't see that as a problem).
To show a message box with the selected item then you just need to do:
MessageBox.Show(DirectCast(listbox1.SelectedItem, Item).ID.ToString))
I think you'll have to write a helper method to do this. If you're using VB 3.5 or newer (part of VS2008 and newer) you can write an extension method so that you can at least get nice syntax. You could write one such that it looked like:
listbox1.SelectByID(123)
listbox1.SelectByName("hello")
In the methods you'd have some search algorithm that went through the items and found the right one.