I have a problem...
I am trying to put into a list of String dictionary keys values if condition of containsvalue is true:
But, this is not correct :(
here is a code:
Private listID As New List(Of String) ' declaration of list
Private dictionaryID As New Dictionary(Of String, Integer) ' declaration of dictionary
'put a keys and values to dictionary
dictionaryID.Add("first", 1)
dictionaryID.Add("second", 2)
dictionaryID.Add("first1", 1)
If dictionaryID.ContainsValue(1) Then ' if value of dictinary is 1
Dim pair As KeyValuePair(Of String, Integer)
listID.Clear()
For Each pair In dictionaryID
listID.Add(pair.Key)
Next
End If
And now, list must have two elements... -> "first" and "first1"
Can you help me?
Thank you very much!
You are looping through the whole dictionary and add all the elements to the list. You should put an if statement in the For Each or use a LINQ query like this:
If listID IsNot Nothing Then
listID.Clear()
End If
listID = (From kp As KeyValuePair(Of String, Integer) In dictionaryID
Where kp.Value = 1
Select kp.Key).ToList()
Using an if statement:
listID.Clear()
For Each pair As KeyValuePair(Of String, Integer) In dictionaryID
If pair.Value = 1 Then
listID.Add(pair.Key)
End If
Next
My VB.Net is a little rusty, but it looks like you were adding all of them, no matter if their value was 1 or not.
Private listID As New List(Of String) ' declaration of list
Private dictionaryID As New Dictionary(Of String, Integer) ' declaration of dictionary
'put a keys and values to dictionary
dictionaryID.Add("first", 1)
dictionaryID.Add("second", 2)
dictionaryID.Add("first1", 1)
If dictionaryID.ContainsValue(1) Then ' if value of dictinary is 1
Dim pair As KeyValuePair(Of String, Integer)
listID.Clear()
For Each pair In dictionaryID
If pair.Value = 1 Then
listID.Add(pair.Key)
End If
Next
End If
Related
I have a KeyValuePair(Of TKey,TValue) and I want to check if it is null or not:
Dim dictionary = new Dictionary(Of Tkey,TValue)
Dim keyValuePair = dictionary.FirstOrDefault(Function(item) item.Key = *someValue*)
If keyValuePair isNot Nothing Then 'not valid because keyValuePair is a value type
....
End If
If keyValuePair <> Nothing Then 'not valid because operator <> does not defined for KeyValuePair(of TKey,TValue)
...
End If
How can I check if keyValuePair is null or not?
KeyValuePair(Of TKey, TValue) is a struct(Structure), it has default value which you can compare to.
Dim dictionary As New Dictionary(Of Integer, string)
Dim keyValuePair = dictionary.FirstOrDefault(Function(item) item.Key = 2)
Dim defaultValue AS KeyValuePair(Of Integer, string) = Nothing
If keyValuePair.Equals(defaultValue) Then
' Not found
Else
' Found
End If
Nothing represents default value of the corresponding type.
But because you are searching Dictionary for a key, you can use TryGetValue instead
Dim dictionary As New Dictionary(Of Integer, string)
Dim value As String
If dictionary.TryGetValue(2, value) Then
' Found
Else
' Not found
End If
Public _SecurityLevel As List(Of KeyValuePair(Of Integer, Integer))
Public Sub New()
_SecurityLevel.Add(New KeyValuePair(Of Integer, Integer)(1, 0))
_SecurityLevel.Add(New KeyValuePair(Of Integer, Integer)(2, 1))
_SecurityLevel.Add(New KeyValuePair(Of Integer, Integer)(3, 2))
_SecurityLevel.Add(New KeyValuePair(Of Integer, Integer)(4, 3))
_SecurityLevel.Add(New KeyValuePair(Of Integer, Integer)(5, 4))
_SecurityLevel.Add(New KeyValuePair(Of Integer, Integer)(6, 5))
End Sub
I want to get the value (3) when I specify the Key (4).
I don't want to iterate through the entire KVP until I find it.
Is this possible? If not what should I be using?
You can get it by using LINQ:
Dim theValue As Integer = _SecurityLevel.Find(Function(kvp) kvp.Key = 4).Value
But I would recommend to use a Dictionary instead, if no duplicate keys should occur.
Dim _SecurityLevel As New Dictionary(Of Integer, Integer)
_SecurityLevel.Add(1, 0)
_SecurityLevel.Add(2, 1)
_SecurityLevel.Add(3, 2)
_SecurityLevel.Add(4, 3)
_SecurityLevel.Add(5, 4)
_SecurityLevel.Add(6, 5)
Dim result As Integer
_SecurityLevel.TryGetValue(4, result)
Edit
As stated in the comments, FindIndex would be the better joice here, as Find will return a default KeyValuePair with key/value (0,0) if no entry is found in the list.
Something like the following would be more reliable:
Dim index As Integer = _SecurityLevel.FindIndex(Function(kvp) kvp.Key = 4)
If index > -1 Then
MsgBox(_SecurityLevel(index).Value)
Else
'Not found
End If
A Dictionary seems more appropriate for your application.
Public Class SomeClass
Public _SecurityLevel As New Dictionary(Of Integer, Integer)
Public Sub New()
_SecurityLevel.Add(1, 0)
_SecurityLevel.Add(2, 1)
_SecurityLevel.Add(3, 2)
_SecurityLevel.Add(4, 3)
_SecurityLevel.Add(5, 4)
_SecurityLevel.Add(6, 5)
End Sub
End Class
Private Sub OPCode()
Dim sc As New SomeClass
Dim v = sc._SecurityLevel(4)
Debug.Print(v.ToString)
'Prints 3
End Sub
It would be unusual to have a public field in a class.
Try this:
Dim valueFromKey As Integer = (From currentValue In _SecurityLevel.AsEnumerable
Where currentValue.Key = 4
Select currentValue.Value).FirstOrDefault
Currently I'm trying to add values into a nested dictionary using VB. I have it working for a flat dictionary, but can't quite get my head around the syntax for doing it nested.
What I have so far is, I have commented the lines I'm having trouble with:
Public Shared Dim dictionary AS New System.Collections.Generic.Dictionary(Of String, System.Collections.Generic.Dictionary(Of String, Integer))
Function addValue(ByVal code AS String, ByVal cust AS String,ByVal value AS Integer)
Dim innerDict AS New System.Collections.Generic.Dictionary(Of String, Integer)
innerDict.Add(cust,value);
IF dictionary.ContainsKey(code) Then
IF dictionary.Item(code).ContainsKey(cust) Then 'Can I access the Customer key in this way?
dictionary.Item(code).Item 'Here I need to update the value held by customer to the old value + new value.
Else
dictionary(code).Add(cust,value) 'Is this syntax correct?
End If
Else
dictionary.Add(code,innerDict)
End If
End Function
What I want to happen is to have a dictionary structured as follow:
Code1:
Customer1: 12
Customer2: 13
Code 2:
Customer1: 12
Customer2: 13
Here is the function that will do what you want.
The first thing it does, is checks whether an entry exists for code in dictionary. If none exists, it adds one whose value is an empty dictionary that will receive the cust-value pairs.
Currently the function does not return any value. If no value is to be returned, you should use a Sub.
Function addValue(ByVal code As String, ByVal cust As String, ByVal value As Integer)
' If no entry for code, create one.
If Not dictionary.ContainsKey(code) Then
dictionary.Add(code, New System.Collections.Generic.Dictionary(Of String, Integer))
End If
' Add cust, value to entry at code.
dictionary(code).Add(cust, value)
End Function
' Returns sum the customer's values.
Function SumCustomerValues(customer As String) As Integer
Dim sum As Integer = 0
For Each d As KeyValuePair(Of String, System.Collections.Generic.Dictionary(Of String, Integer)) In dictionary
If d.Value.ContainsKey(customer) Then
sum += d.Value(customer)
End If
Next
Return sum
End Function
I need to create a 2D dictionary/keyvalue pair.
I tried something like this.
Dim TwoDimData As New Dictionary(Of String, Dictionary(Of String, String))
'Create an empty table
For Each aid In AIDList '(contains 15000 elements)
TwoDimData.Add(aid, New Dictionary(Of String, String))
For Each bid In BIDList 'contains 30 elements
TwoDimData.Item(aid).Add(bid, "")
Next
Next
'Later populate values.
[some code here to populate the table]
'Now access the value
'The idea is to access the info as given below (access by row name & col name)
Msgbox TwoDimData.Item("A004").Item("B005") ' should give the value of 2
Msgbox TwoDimData.Item("A008").Item("B002") ' should return empty string. No error
Issue:
The issue is in Creating the empty table. It takes 70 seconds to create the TwoDimData table with empty values. Everything else seems to be fine. Is there any way to improve the performance - may be instead of using Dictionary?
I suggest you try Dictionary(Of Tuple(Of String, String), String) instead. That is, the keys are pairs of strings (Tuple(Of String, String)) and the values are strings. That would appear to correspond nicely to the diagram in your question.
Dim matrix As New Dictionary(Of Tuple(Of String, String), String)
' Add a value to the matrix:
matrix.Add(Tuple.Create("A003", "B004"), "3")
' Retrieve a value from the matrix:
Dim valueAtA003B004 = matrix(Tuple.Create("A003", "B004"))
Of course you can define your own key type (representing a combination of two strings) if Tuple(Of String, String) seems too generic for your taste.
Alternatively, you could also just use (possibly jagged) 2D arrays, but that would potentially waste a lot of space if your data is sparse (i.e. if there are many empty cells in that 2D matrix); and you'd be forced to use numeric indices instead of strings.
P.S.: Actually, consider changing the dictionary value type from String to Integer; your example matrix suggests that it contains only integer numbers, so it might not make sense to store them as strings.
P.P.S.: Do not add values for the "empty" cells to the dictionary. That would be very wasteful. Instead, instead of simply retrieving a value from the dictionary, you check whether the dictionary contains the key:
Dim valueA As String = "" ' the default value
If matrix.TryGetValue(Tuple.Create("A007", "B002"), valueA) Then
' the given key was present, and the associated value has been retrieved
…
End If
I would think that a simple structure would suffice for this?
Public Structure My2DItem
Public Row As Integer
Public Col As Integer
Public Value As String
End Structure
Public My2DArray As Generic.List(Of My2DItem) = Nothing
Public Size As Integer
Public MaxRows As Integer
Public MaxCols As Integer
'
Sub Initialise2DArray()
'
Dim CountX As Integer
Dim CountY As Integer
Dim Item As My2DItem
'
'initialise
MaxRows = 15000
MaxCols = 30
Size = MaxRows * MaxCols
My2DArray = New Generic.List(Of My2DItem)
'
'Create an empty table
For CountY = 1 To 15000
For CountX = 1 To 30
Item = New My2DItem
Item.Row = CountY
Item.Col = CountX
Item.Value = "0"
My2DArray.Add(Item)
Item = Nothing
Next
Next
'
End Sub
And to read the data out of the array,
Function GetValue(Y As Integer, X As Integer) As String
'
Dim counter As Integer
'
GetValue = "Error!"
If My2DArray.Count > 0 Then
For counter = 0 To My2DArray.Count - 1
If My2DArray(counter).Row = Y Then
If My2DArray(counter).Col = X Then
GetValue = My2DArray(counter).Value
Exit Function
End If
End If
Next
End If
'
End Function
And to read your sample cell A004 B005
MyStringValue = GetValue(4,5)
I would suggest creating a class that has properties for the AID and BID and use this as the basis for the values you want to store
Public Class AIdBId
Public Property AId As Integer
Public Property BId As Integer
Public Sub New(aId As Integer, bId As Integer)
Me.AId = aid
Me.BId = bid
End Sub
End Class
Note that I have used integers for everything because it seems that is all you need and it is more efficient that using a string
Then you can add values where they are non-zero:
'define your dictionary
Dim valueMatrix As New Dictionary(Of AIdBId, Integer)
'add your values
valueMatrix.Add(New AIdBId(1, 1), 1)
valueMatrix.Add(New AIdBId(2, 3), 1)
valueMatrix.Add(New AIdBId(4, 3), 3)
valueMatrix.Add(New AIdBId(5, 8), 8)
'check if a value exixts
Dim valueExixsts As Boolean = valueMatrix.ContainsKey(New AIdBId(9, 9))
'get a value
Dim i As Integer = valueMatrix(New AIdBId(4, 3))
So you can now combine these two to return the value if there is one or zero if not:
Private Function GetValue(valuematrix As Dictionary(Of AIdBId, Integer), aId As Integer, bId As Integer) As Integer
Dim xRef As New AIdBId(aId, bId)
If valuematrix.ContainsKey(xRef) Then
Return valuematrix(xRef)
Else
Return 0
End If
End Function
I declare my 2D lists:
Dim _invoiceitems As New List(Of List(Of String))
Dim _dbitems As New List(Of List(Of String))
Each List is filled like this:
Example Code To fill:
_invoiceitems.Add(New List(Of String))
_invoiceitems(0).Add("Code #")
_invoiceitems(0).Add("Quantity")
Well, now i need a third list called (_changesitems) Note that this result with the differences:
be the result of subtraction of quantities if this is found (dbitems - invoiceitems).
How i can get this result?
The following code will generate the results you are looking for:
Private Function getChangesItems(ByVal invoiceItems As Dictionary(Of String, Integer), ByVal dbItems As Dictionary(Of String, Integer)) As Dictionary(Of String, Integer)
Dim changesItems As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)()
Dim allCodes As List(Of String) = New List(Of String)()
allCodes.AddRange(invoiceItems.Keys)
allCodes.AddRange(dbItems.Keys)
For Each code As String In allCodes
If Not changesItems.ContainsKey(code) Then
Dim dbQuantity As Integer = 0
Dim invoiceQuantity As Integer = 0
If dbItems.ContainsKey(code) Then
dbQuantity = dbItems(code)
End If
If invoiceItems.ContainsKey(code) Then
invoiceQuantity = invoiceItems(code)
End If
Dim changeQuantity As Integer = dbQuantity - invoiceQuantity
If changeQuantity <> 0 Then
changesItems.Add(code, changeQuantity)
End If
End If
Next
Return changesItems
End Function
I used dictionaries instead of lists as was recommended by others. As long as your data only contains a code and a value, the dictionary is a better fit. If you have more columns, I would suggest creating a class that contains properties for each column and then make a list of that class type, rather than a simple 2D list of strings. Doing so would be more type-safe and easier to read.