Link to home
Start Free TrialLog in
Avatar of BASit Bulbulia
BASit BulbuliaFlag for South Africa

asked on

How to search for part of a dictionary key (.net vb visual studio 2008)

Could someone please tell me, how I can search for only a part of a key in a dictionary (in VB.NET)?

I use the following sample code:

    Dim PriceList As New Dictionary(Of String, Double)

    PriceList.Add("Spaghetti alla carbonara", 21.65)
    PriceList.Add("Spaghetti aglio e olio", 22.65)
    PriceList.Add("Spaghetti alla napoletana", 23.65)
    PriceList.Add("Spaghetti alla puttanesca ", 24.65)
    PriceList.Add("Spaghetti alla gricia ", 25.65)
    PriceList.Add("Spaghetti alle vongole", 26.65)
    PriceList.Add("Spaghetti Bolognese", 27.65)

    If PriceList.ContainsKey("spaghetti bolognese") Then
        Dim price As Double = PriceList.Item("spaghetti bolognese")
        Console.WriteLine("Found, price: " & price)
    End If

    If Not PriceList.ContainsKey("Bolognese") Then
        Console.WriteLine("How can I search for only a part of a key?")
    End If


If I only know a part of the key like "Bolognese" or just a part of word like "Bolo", how can I search for this part in the complete key?
Avatar of Wayne Taylor (webtubbs)
Wayne Taylor (webtubbs)
Flag of Australia image

You'll find the answer in the question you asked at that other site.
SOLUTION
Avatar of Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger)
Flag of Canada image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of BASit Bulbulia

ASKER

@webtubbs - > The solution at the other site does not work as the Pricelist.where (generates an error) -> for those who are interested in finding a better solution or have a work around the error - please visit :-

http://stackoverflow.com/questions/17998321/how-to-search-for-a-part-of-a-dictionary-key

@James Burger -> Your method requires a loop through the whole array and it ain't efficient and defeats the purpose of the dictionary hash.
A Hash is a numeric or condensed representation of a specific string in its whole. Entries in the directory are sorted by that hash, so this is why it is efficient. It is useful to search for the whole string, but otherwise worthless.

It's a bit similar as an index on a string value in a database. Search for the whole content of the field, and it zips through. But as soon as you start looking for anything that is not the beginning of the string, by the use of LIKE for instance, you defeats its purpose because the index becomes useless.
Hi compubyte-sa;

Try the code snippet below, it should give you what you need.

Dim searchTerm As String = "Bolo"
Dim price As KeyValuePair(Of String, Double) = PriceList.Where(Function(k) k.Key.Contains(searchTerm)).FirstOrDefault()

If price.Key IsNot Nothing Then 
    Console.WriteLine("Found, price: " + price.Value.ToString() )
End If

Open in new window

@Fernando - I have used this code before and in Visual Studio .net 2008 I get an error -> Error      1      'Where' is not a member of 'System.Collections.Generic.Dictionary(Of String, Integer)'.      

Pic enclosed !

Full code below :-

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim DealDetail As New Dictionary(Of String, Integer)
        Dim x As Integer = 0

        Dim ffile As String = "\ums\dealdetail.csv"
        Dim f As Integer = FreeFile()

        If File.Exists(ffile) Then
            FileOpen(f, ffile, OpenMode.Input)
            While EOF(f) = False
                x = x + 1
                DealDetail.Add(LineInput(f) + Str(x), x)
                '    Dim items() As String = Split(tzz, ";")
            End While
            FileClose(f)
        End If

        Dim PriceList As New Dictionary(Of String, Integer)
        x = 0
        ffile = "\ums\pricelist.csv"
        f = FreeFile()
        If File.Exists(ffile) Then
            FileOpen(f, ffile, OpenMode.Input)
            While EOF(f) = False
                x = x + 1
                PriceList.Add(LineInput(f) + Str(x), x)
                '    Dim items() As String = Split(tzz, ";")
            End While
            FileClose(f)
        End If

        Dim Product As New Dictionary(Of String, Integer)
        x = 0
        ffile = "\ums\product.csv"
        f = FreeFile()
        If File.Exists(ffile) Then
            FileOpen(f, ffile, OpenMode.Input)
            While EOF(f) = False
                x = x + 1
                Product.Add(LineInput(f) + Str(x), x)
                '    Dim items() As String = Split(tzz, ";")
            End While
            FileClose(f)
        End If

        Dim Suppliers As New Dictionary(Of String, Integer)
        ffile = "\ums\suppliers.csv"
        f = FreeFile()
        If File.Exists(ffile) Then
            FileOpen(f, ffile, OpenMode.Input)
            While EOF(f) = False
                x = x + 1
                Suppliers.Add(LineInput(f) + Str(x), x)
                '    Dim items() As String = Split(tzz, ";")
            End While
            FileClose(f)
        End If

        x = 0
        Dim y As Integer
        Dim Z As Integer
        Dim ZZ As Integer


        Dim DiscountValue As Single
        Dim DiscountPercentage As Single
        Dim PriceN As Single
        Dim Sup As String

        Dim FoundItem As Boolean = False


        Dim pair As KeyValuePair(Of String, Integer)

        For Each pair In DealDetail

            Sup = "Unknown"
            FoundItem = False

            Label1.Text = Str(pair.Value) + " of" + Str(DealDetail.Count)

            Application.DoEvents()

            Dim items() As String = Split(pair.Key, ";")

            StartDate.Add(items(4))
            EndDate.Add(items(5))
            DiscountValue = Val(items(11))
            DiscountPercentage = Val(items(12))

            Dim searchTerm As String = "Bolo"
            Dim price As KeyValuePair(Of String, Single) = Product.Where(Function(k) k.Key.Contains(searchTerm)).FirstOrDefault()

            If price.Key IsNot Nothing Then
                Console.WriteLine("Found, price: " + price.Value.ToString())
            End If



            If Product.ContainsKey(items(3)) Then
                MsgBox("Found ! ! ! ")
            End If


        Next

Open in new window

error.where.jpg
Where appeared in framework 3.5. If you are targeting an older version, it's not there.

Anyway, what do you think Where does in the background?

If you know about hashtables, you know that it needs to loop through the items until it finds one whose key contains the substring you are looking for. There is no way to use the optimisation of the hash in any kind of hashtable unless you look for the whole key.
Let's look at what has been recommended here:
Module Module1
	Private ReadOnly watch As New Stopwatch()
	Private ReadOnly PriceList As New Dictionary(Of String, Double)() From {{"Spaghetti alla carbonara", 21.65}, {"Spaghetti aglio e olio", 22.65}, {"Spaghetti alla napoletana", 23.65}, {"Spaghetti alla puttanesca ", 24.65}, {"Spaghetti alla gricia ", 25.65}, {"Spaghetti alle vongole", 26.65}, {"Spaghetti Bolognese", 27.65}}

	Sub Main()
		Console.WriteLine("Let's do some calculations:")
		DictionaryWhere()
		KeyWhere()
		StandardFor()
		Console.ReadLine()
	End Sub

	Sub DictionaryWhere()
		Console.WriteLine()
		Console.WriteLine("Using a dictionary based where clause")
		watch.Reset()
		watch.Start()
		Dim result As KeyValuePair(Of String, Double) = PriceList.Where(Function(k) k.Key.Contains("Bologne")).FirstOrDefault()
		watch.Stop()

		If Not String.IsNullOrEmpty(result.Key) Then
			Console.WriteLine("Found: {0} for {1}", result.Key, result.Value)
		Else
			Console.WriteLine("Could not find search item")
		End If
		Console.WriteLine("Using a dictionary based where clause took {0} ms", watch.ElapsedMilliseconds)
	End Sub

	Sub KeyWhere()
		Console.WriteLine()
		Console.WriteLine("Using a key based where clause")
		watch.Reset()
		watch.Start()
		Dim result As KeyValuePair(Of String, Double) = (From item In PriceList Where item.Key.Contains("Bologne") Select item).FirstOrDefault()
		watch.Stop()

		If Not String.IsNullOrEmpty(result.Key) Then
			Console.WriteLine("Found: {0} for {1}", result.Key, result.Value)
		Else
			Console.WriteLine("Could not find search item")
		End If
		Console.WriteLine("Using a key based where clause took {0} ms", watch.ElapsedMilliseconds)
	End Sub

	Sub StandardFor()
		Console.WriteLine()
		Console.WriteLine("Using a standard forloop")
		watch.Reset()
		watch.Start()
		Dim result As New KeyValuePair(Of String, Double)
		With PriceList
			For i As Integer = 0 To .Keys.Count - 1
				If .Keys(i).IndexOf("Bologne") > -1 Then
					result = .ElementAt(i)
					Exit For
				End If
			Next
		End With
		watch.Stop()

		If Not String.IsNullOrEmpty(result.Key) Then
			Console.WriteLine("Found: {0} for {1}", result.Key, result.Value)
		Else
			Console.WriteLine("Could not find search item")
		End If
		Console.WriteLine("Using a standard forloop took {0} ms", watch.ElapsedMilliseconds)
	End Sub
End Module

Open in new window

Which produces the following output (results will vary) -User generated imageAs you can see here, the for loop (which is really what linq does when you come down to it), performs this search a millisecond faster than the key based search.  The key based search is, essentially, an expanded expression based statement that does the same lookup as using the Method based dictionary.Where lookup.

Draw your own conclusions but James still has the better method.

-saige-
@saige - thank you for response - it does show that James method is the fastest !
it does show that James method is the fastest
It does show that net framework cash queries. Try
    Sub Main()
        Console.WriteLine("Let's do some calculations:")
        StandardFor()
        KeyWhere()
        DictionaryWhere()
        Console.ReadLine()
    End Sub

Open in new window

A slightly changed code
Module Module1
    Private ReadOnly watch As New Stopwatch()
    Private ReadOnly PriceList As New Dictionary(Of String, Double)() From {{"Spaghetti alla carbonara", 21.65}, {"Spaghetti aglio e olio", 22.65}, {"Spaghetti alla napoletana", 23.65}, {"Spaghetti alla puttanesca ", 24.65}, {"Spaghetti alla gricia ", 25.65}, {"Spaghetti alle vongole", 26.65}, {"Spaghetti Bolognese", 27.65}}
    Private result As KeyValuePair(Of String, Double)
    Private passes As Integer = 100000

    Sub Main()
        Console.WriteLine("Let's do some calculations:")
        KeyWhere()
        DictionaryWhere()
        StandardFor()
        Console.ReadLine()
    End Sub

    Sub DictionaryWhere()
        result = New KeyValuePair(Of String, Double)
        watch.Reset()
        watch.Start()
        For i = 1 To passes
            result = PriceList.Where(Function(k) k.Key.Contains("Bologne")).FirstOrDefault()
        Next
        watch.Stop()
        Console.WriteLine("Using a dictionary based where clause took {0} ms", watch.ElapsedMilliseconds)
    End Sub

    Sub KeyWhere()
        result = New KeyValuePair(Of String, Double)
        watch.Reset()
        watch.Start()
        For i = 1 To passes
            Dim key = (From x In PriceList.Keys Where x.Contains("Bologne")).FirstOrDefault
            result = New KeyValuePair(Of String, Double)(key, PriceList(key))
        Next
        Console.WriteLine("Using a key based where clause took {0} ms", watch.ElapsedMilliseconds)
    End Sub

    Sub StandardFor()
        result = New KeyValuePair(Of String, Double)
        watch.Reset()
        watch.Start()
        For j = 1 To passes
            With PriceList
                For i As Integer = 0 To .Keys.Count - 1
                    If .Keys(i).IndexOf("Bologne") > -1 Then
                        result = .ElementAt(i)
                        Exit For
                    End If
                Next
            End With
        Next
        watch.Stop()
        Console.WriteLine("Using a standard forloop took {0} ms", watch.ElapsedMilliseconds)
    End Sub
End Module

Open in new window

User generated image
@Ark Ummmm very interesting  ! !
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks guys  ! !