Forum Discussion

MarcR's avatar
4 years ago

Dictionary with ValueTuple as the key

Hi there, 

I want to add data to a dictionary with a key that contains 3 fields. I've been advised to use a ValueTuple but have tried all the syntax options that i could find in Google without success.

 

Ideally it should be like the setup of a databuffer where the key is the databuffercellPk and the value the actual stored number.

My key should contain 3 strings and the value a decimal).

I've tried something like: Dim dctDict as New Dictionary<(String sn, String Tm, String Ac)>, int();

and various other options. 

Does anybody had a suggestion how to create the best performing Dictionary Key that exists of 3 strings?

  •  

    Sub Main
    
    	'Initialize collection of data keys
    	Dim dkCollection As New Dictionary(Of dataKey, Integer)
    
    	For i = 1 To 12
    		Dim dk As New dataKey()
    		dk.sn = "Actual"
    		dk.tm = $"2020M{i}"
    		dk.ac = "Sales"
    		dkCollection.Add(dk, 10 * i)
    	Next i
    
    	'Generate a new key and serach for it
    	Dim searchDk As New dataKey()
    	searchDk.sn = "Actual"
    	searchDk.tm = "2020M2"
    	searchDk.ac = "Sales"
    
    	'Search single key	
    	Dim resultDk1 As Integer = dkCollection.Item(searchDk)
    	Console.WriteLine($"Single Query Result = {resultDk1}")
    
    	'Search multiple keys
    	Dim resultList As List(Of Integer) = dkCollection.Where(Function(x) x.Key.sn = "Actual").Select(Function(y) y.Value).ToList
    		Console.WriteLine($"Single Query Result = {String.Join(",", resultList)}")
    
    End Sub
    
    ' Define other methods and classes here
    ' Define other methods and classes here
    Private Structure dataKey
    	Property sn As String
    	Property tm As String
    	Property ac As String
    End Structure

     

    The struct can be generated iteratively, in this case in a for loop. When you search for it you can generate a new struct and if all the property are the same it will match what is in the collection. Essentially the struct itself is just a memory pointer, so you can definitely generate them in a loop. Clearly if you try to add a struct with the same three properties, even if the "name" you give to the object is different, it will return an error, since the name of the object itself exist only in the code you see,  but not in the compiled version the machine is going to run. Essentially it is just a label to avoid you from knowing the memory location of the object. 

    Single Query Result = 20
    Single Query Result = 10,20,30,40,50,60,70,80,90,100,110,120
  • What about creating a structure with your three keys and use that as a key for the dictionary? You can then generate a complete search key if you know all the parameters or you can use Linq to query the keys for a single dimension

     

     

    Sub Main
    	
    	'Initialize collection of data keys
    	Dim dkCollection As New Dictionary(Of dataKey, Integer)
    
    	'Data key 1
    	Dim dk1 As New dataKey()
    	dk1.sn = "Actual"
    	dk1.tm = "202M1"
    	dk1.ac = "Sales"
    	dkCollection.Add(dk1, 10)
    
    	'Data key 2
    	Dim dk2 As New dataKey()
    	dk2.sn = "Actual"
    	dk2.tm = "202M2"
    	dk2.ac = "Sales"
    	dkCollection.Add(dk2, 20)
    
    	'Generate a new key and serach for it
    	Dim searchDk As New dataKey()
    	searchDk.sn = "Actual"
    	searchDk.tm = "202M2"
    	searchDk.ac = "Sales"
    
    	'Search single key	
    	Dim resultDk1 As Integer = dkCollection.Item(searchDk)
    
    	'Search multiple keys
    	Dim resultList As List(Of Integer) = dkCollection.Where(Function(x) x.Key.sn = "Actual").Select(Function(y) y.Value).ToList
    	
    	
    End Sub
    
    ' Define other methods and classes here
    Private Structure dataKey
    	Property sn As String
    	Property tm As String
    	Property ac As String
    End Structure

     

    Single Query Result: 20
    Multiple Query Results: 10,20
    • ChristianW's avatar
      ChristianW
      Valued Contributor

      This is what the platform is doing (more or less) with the PK classes.

    • MarcR's avatar
      MarcR
      VIP

      Hi Tommaso,

      I will test this one later this week and let you know!

    • MarcR's avatar
      MarcR
      VIP

      One additional question, I will add multiple keys, is there a way (next to updating the key) to dim a parameter with a counter? E.g. 

      for i = 1 to 3

      dim key as “key” & I as datakey

      next 

       

      I know this example is not working but perhaps there is something to put around “key” & I to make it work.

      • tsandi's avatar
        tsandi
        Contributor

         

        Sub Main
        
        	'Initialize collection of data keys
        	Dim dkCollection As New Dictionary(Of dataKey, Integer)
        
        	For i = 1 To 12
        		Dim dk As New dataKey()
        		dk.sn = "Actual"
        		dk.tm = $"2020M{i}"
        		dk.ac = "Sales"
        		dkCollection.Add(dk, 10 * i)
        	Next i
        
        	'Generate a new key and serach for it
        	Dim searchDk As New dataKey()
        	searchDk.sn = "Actual"
        	searchDk.tm = "2020M2"
        	searchDk.ac = "Sales"
        
        	'Search single key	
        	Dim resultDk1 As Integer = dkCollection.Item(searchDk)
        	Console.WriteLine($"Single Query Result = {resultDk1}")
        
        	'Search multiple keys
        	Dim resultList As List(Of Integer) = dkCollection.Where(Function(x) x.Key.sn = "Actual").Select(Function(y) y.Value).ToList
        		Console.WriteLine($"Single Query Result = {String.Join(",", resultList)}")
        
        End Sub
        
        ' Define other methods and classes here
        ' Define other methods and classes here
        Private Structure dataKey
        	Property sn As String
        	Property tm As String
        	Property ac As String
        End Structure

         

        The struct can be generated iteratively, in this case in a for loop. When you search for it you can generate a new struct and if all the property are the same it will match what is in the collection. Essentially the struct itself is just a memory pointer, so you can definitely generate them in a loop. Clearly if you try to add a struct with the same three properties, even if the "name" you give to the object is different, it will return an error, since the name of the object itself exist only in the code you see,  but not in the compiled version the machine is going to run. Essentially it is just a label to avoid you from knowing the memory location of the object. 

        Single Query Result = 20
        Single Query Result = 10,20,30,40,50,60,70,80,90,100,110,120
  • ChristianW's avatar
    ChristianW
    Valued Contributor

    As ugly as it looks, I think, there is no alternative to:

     

     

    dim dctDict as new dictionary(of dictionary(of string, string), integer)
    
    dim dctDict as new dictionary(of string, dictionary(of string, integer))
    
    Dim dctDict As New dictionary(Of Tuple(Of String, String), Integer)

     

     

    • MarcR's avatar
      MarcR
      VIP

      Hi Christian, 

      That would also be an issue to get the data in and out of this dictionary. My alternative would be to delimit the items with a pipe and then combine the search fields to this unique key. The only disadvantage is that i cannot search for a specific key (or filter on that). Ideally i would work with it as we do with a datacellPK but i don't see any better solution right now.

       

      • ChristianW's avatar
        ChristianW
        Valued Contributor

        Did you try this:

         

        dctDict3.add(New tuple(Of String, String)("Christian", "Marc"), 100)
        
        brapi.ErrorLog.LogMessage(si, dctDict3(New tuple(Of String, String)("Christian", "Marc")))