3

For me it seems to be obvious that a dictionary might have a method for getting it's item by Key. Either I am blind, or... However, I have following situation:

A need a Dictionary(Of Integer, k/v). I have the k/v's already in a Dictionary and I'd like to add them to my new one by Key, such as:

'Dict1 has {("Key1", 123), ("Key2", 345)}
Dim dict2 As New Dictionary (Of Integer, KeyValuePair(Of String, Double))
dict2.Add(0,***dict1.GetItem("Key1")***)

Sure I could write an extension, and probably I'll have to, but is it only me missing this function? If there was a built in way I've overseen, please point me there!

Thanks in advance,

Daniel


EDIT:

dict1 = {(0, "apples"), (1, "oranges"), (2, "bananas")}
dict2 = {("oranges", 456), ("apples", 123), ("bananas", 789)}

the new dictionary is a sorted dict2 by dict1:

dictnew = {("apples", 123), ("oranges", 456), ("bananas", 789)}

So my approach was:

dicttemp = {(0, ("apples", 123)), (1, ("oranges", 456)), (2, ("bananas", 789))}'. `dicttemp` is a `SortedDictionary`.

Next I get the values of dicttemp and transform them into a Dictionary.

Vandrey
  • 531
  • 1
  • 8
  • 23
dba
  • 1,159
  • 1
  • 14
  • 22
  • Do you want to build a second dictionary from a first where the key of the new dictionary is the index of the first dictionary and the value is it's KeyValuePair? – Tim Schmelter Sep 02 '14 at 09:48
  • No, the Keys for the new one comes from diff source. Anyhow, I Update my Question to clarify the whole task :) Generall was just wondering I cant access the dict items directly... – dba Sep 02 '14 at 09:57

2 Answers2

4

You're looking for dictionary's indexer.

Dim a As Double = dict1("Key1")

In some comment, OP said:

I need the whole item as k/v and add the item of dict1 to dict2!!!

Since a dictionary implements IEnumerable(Of T) where T is KeyValuePair(Of TKey, TValue), you can use Single(...) LINQ extension method to find out a key-value pair by key:

Dim pair As KeyValuePair(Of String, Double) = dict1.Single(Function(item) item.Key = "key")

Since dictionary's Add method has an overload to give a key-value pair as argument, I believe that adding dict1 key-value pair to dict2 is just about calling Add in the second dictionary providing the obtained key-value pair from first dictionary:

dict2.Add(pair);
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • This returns the value of the dict-item... I need the whole item as k/v and add the item of dict1 to dict2!!! – dba Sep 02 '14 at 09:03
  • Thanks for the answer, I wasn't aware of the LINQ-Method. Anyway, I just implemented a Dictionary Extension, so I simplified the inline call for the k/v-pair (since this is in a loop...) – dba Sep 02 '14 at 09:30
  • @dba I believe that simplifying `Single` is useless, I understand that you want to get rid of lambdas and closures in that loop... but it's just about get used with it! – Matías Fidemraizer Sep 02 '14 at 09:31
  • wasnt using "Single" in the Extension. Rather a for each and testing the Key. AFAIK lambdas working similary at the base... May be wrong :) Thanks for the answers! – dba Sep 02 '14 at 09:38
  • @dba Well lambdas are just expressions. But you're right if you point to the fact that LINQ is just a bunch of specialized *for-feachs* behind a beautiful syntactic sugar :D You can also use `SingleOrDefault` so if the key doesn't exist, it will return null or default value for the dictionary values type. – Matías Fidemraizer Sep 02 '14 at 09:42
0

So you have already the key, the only part missing is the value. Therefore you use the indexer or TryGetValue. Then you have both parts and you can add them to the other dictionary.

Dim dict1 As New Dictionary(Of String, Double) From {{"Key1", 123}, {"Key2", 345}}
Dim dict2 As New Dictionary(Of Integer, KeyValuePair(Of String, Double))
Dim keyVal = New KeyValuePair(Of String, Double)("Key1", dict1("Key1"))
dict2.Add(0, keyVal)

Here is the TryGetValue approach:

Dim d As Double
If dict1.TryGetValue("Key1", d) Then
    dict2.Add(0, New KeyValuePair(Of String, Double)("Key1", d))
End If

For the sake of completeness, you could use LINQ although this would be slow and pointless:

Dim keyVal = dict1.FirstOrDefault(Function(kv)kv.Key = "Key1")

Now you are using a dictionary like a collection which goes against the purpose of the class. This actually loops all items until one is found with a given key.


For what it's worth, since you've asked for a method that returns a KeyValuePair for a given key. Here is an extension method:

<Extension()>
Public Function TryGetKeyValue(Of TKey, TValue)(dictionary As Dictionary(Of TKey, TValue), key As TKey) As KeyValuePair(Of TKey, TValue)?
    Dim value As TValue
    If dictionary.TryGetValue(key, value) Then
        Return New KeyValuePair(Of TKey, TValue)(key, value)
    End If
    Return Nothing
End Function

You use it in this way:

Dim keyVal As KeyValuePair(Of String, Double)? = dict1.TryGetKeyValue("Key1")
If keyVal.HasValue Then dict2.Add(0, keyVal.Value)

It is a O(1) operation, so it's more efficient than using LINQ.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Hi, I know, how to workaround, the question is, if there is a built-in Method for this. :) Thanks anyway! – dba Sep 02 '14 at 09:33
  • @dba: No, you could use `dic1.FirstOrDefault(Function(kv)kv.Key="Key1")`, but that is very slow and pointless. I've added that to the answer althoug i strongly advise agains. – Tim Schmelter Sep 02 '14 at 09:35
  • @dba: the point is that it's not a workaround since you have already the key and you are only looking for the value. So no, there is no builtin method that supports `O(1)` lookup performance and returns a `KeyValuePair` by a given key. – Tim Schmelter Sep 02 '14 at 09:44
  • the point is that I'm not lookig for the value, but the item as keyvaluepair BY the key :) I wanted to avoid define new KeyvaluePairs on the fly... That was the main point... By defining temp vars and filling them with info just to add them "anonymously" is for me a workaround :) – dba Sep 02 '14 at 09:48
  • @dba: since `KeyValuePair(Of TKey, TValue)` is a value type(`Structure`) you are always creating new objects anway(`Object.ReferenceEquals` would always returns false) even if you use `dict2.Add(0, dict1.First())`. Side-note: A sorted dictionary is also [against the purpose of this class](http://stackoverflow.com/questions/25619550/order-when-iterating-over-an-dictionary#comment40024289_25619550) ;-) – Tim Schmelter Sep 02 '14 at 10:04