How do I write this lambda select method in VB.net? - vb.net

For I've tried this:
Dim exampleItems As Dictionary(Of String, String) = New Dictionary(Of String, String)
Dim blah = exampleItems.Select (Function(x) New (x.Key, x.Value)).ToList 'error here
But I'm getting a syntax error and all the examples that I've seen are in C#.

This would be:
Dim blah = exampleItems.Select (Function(x) New With { .Key = x.Key, .Value = x.Value }).ToList
For details, see Anonymous Types. (Depending on usage, you might also want Key or Value to be flagged with the Key keyword.)
That being said, Dictionary(Of TKey, Of TValue) already is an IEnumerable(Of KeyValuePair(Of TKey, Of TValue), so you can also just do:
Dim blah = exampleItems.ToList
And you'll have a list of KeyValuePair, which has a Key and Value property already. This really means there's no need to make the anonymous type.

Related

Convert Dictionary(Of String, Object) to Dictionary(Of String, String)

When I try to pass a Dictionary(Of String, Object) to a function parameter that wants a Dictionary(Of String, String) I get the following error:
Unable to cast object of type 'System.Collections.Generic.Dictionary'2[System.String,System.Object]' to type 'System.Collections.Generic.Dictionary'2[System.String,System.String]'.
All of the Object values in the dictionary are strings but the dictionary was declared as String/Object. I would have thought that the system would be able to convert this but since it isn't I need to do it myself.
I looked at the .ToDictionary() prototype method but all of the examples show a list being converted to a dictionary.
I found this question which has an accepted answer for what I want but it's written in C# and I can't figure out the conversion to VB.Net.
Edit 1
Offending code. Obviously boiled down or else I would just simply declare dict1 as string/string in my actual code.
Dim dict1 As New Dictionary(Of String, Object) From {{"key1","value1"}}
SomeFunctionThatExpectsParamToBeDictOfStringString(dict1)
Edit 2
I tried:
SomeFunctionThatExpectsParamToBeDictOfStringString(dict1.ToDictionary(Function(k) k.Key, Function(v) v.Value.ToString()))
but got:
System.MissingMemberException: Public member 'ToDictionary' on type 'Dictionary(Of String,Object)' not found.
This could be the VB.NET version of the C# code you have linked
Dim dic1 As Dictionary(Of String, Object) = New Dictionary(Of String, Object)
dic1.Add("A", "B")
Dim dic2 As Dictionary(Of String, String) = dic1.ToDictionary(Function(k) k.Key,
Function(v) v.Value.ToString())

how to convert value in a keypairs into list?

Dim dict As New Dictionary(Of String, KeyValuePair(Of String, String))
dict.Add("key", New KeyValuePair(Of String, String)("value1","value2"))
I want to get value2 as a list.
Using LINQ Extensions:
' use KeyValuePair of dictionary, that gives 2 levels of KeyValuePairs
Dim list = dict.Select(function(kvp) kvp.Value.Value).ToList()
' Or use the Values part of Dictionary
Dim list = dict.Values.Select(function(v) v.Value).ToList()
' Adding some conditional and getting value1 instead:
Dim list = dict.Values.Where(function(k) k.Value = "value2").Select(function(v) v.Key).ToList()
For KeyValuePair x.Key is "value1" and x.Value is "value2"
Please note that this will get quite slow on big Dictionarys and there is probably better ways to handle this, but that requires more information about The actual use-case.

How to sort the keys of a dictionary in reverse order using VB.NET?

I have a dictionary:
Dim dicItems As Dictionary(of Integer, String)
The items in the dictionary are:
1,cat
2,dog
3,bird
I would like the order to be:
3,bird
2,dog
1,cat
You can't sort a dictionary, what you need is a sorted list instead.
Dim dicItems As New SortedList(Of Integer, String)
This will sort the items by the key value. If you want to get the items out in descending order like your example you could always do a loop starting from the end of the list, and moving to the beginning.
The below link has more information on SortedList's.
http://msdn.microsoft.com/en-us/library/ms132319%28v=vs.110%29.aspx
You can use LINQ to solve this easily:
Dim dicItems As New Dictionary(Of Integer, String)
With dicItems
.Add(1, "cat")
.Add(2, "dog")
.Add(3, "bird")
End With
dim query = from item in dicItems
order by item.Key descending
select item
If you want, you can also use the Lambda syntax:
Dim query = dicItems.OrderByDescending(Function(item) item.Key)
A dictionary has no implicit order that you can rely on ("The order in which the items are returned is undefined").
As add-on for Shadows answer who suggest to use a SortedList you can get descending order by using the constructor that takes an IComparer(Of Int32):
Dim list = New SortedList(Of Integer, String)(New DescendingComparer())
list.Add(3, "bird")
list.Add(1, "cat")
list.Add(2, "dog")
Public Class DescendingComparer
Implements IComparer(Of Int32)
Public Function Compare(x As Integer, y As Integer) As Integer Implements System.Collections.Generic.IComparer(Of Integer).Compare
Return y.CompareTo(x)
End Function
End Class
Not sure why you would want to, since an order of items in the dictionary usually does not matter, but you can do it like this:
Dim dicItems As New Dictionary(Of Integer, String)
With dicItems
.Add("1", "cat")
.Add("2", "dog")
.Add("3", "bird")
End With
Dim dicItemsReversed As New List(Of KeyValuePair(Of Integer, String))
dicItemsReversed.AddRange(dicItems.Reverse())
Notice that I output to a different collection, i.e. Generic.List in this case. If you want to replace your original contents, you can then do this:
dicItems.Clear()
For Each kv In dicItemsReversed
dicItems.Add(kv.Key, kv.Value)
Next
As a variation on the topic, you can replace dicItems.Reverse() with other LINQ alternatives, such as OrderBy, so you can, for example, sort by Key, Value or a combination thereof. For example this dicItems.OrderBy(Function(x) x.Value) gives the output of:
3,bird
1,cat
2,dog
(sorted alphabetically by value, ascending order)

List of Dictionary Arrays

Hit a wall, and can't find much in docs.
I have two dictionaries, and I'd like to put them in a list.
Dim listOfDictionaries As List(Of Dictionary(Of String, String))
is not working.
Am I correct in assuming that once I get this dimmed, I can .add the conventional way?
Details (EDIT)
When trying to listOfDictionaries.Add(dictionaryIWantToAdd), I get "value of type '1-dimensional array system.collection.generic.dictionary(of string, string)' cannot be converted to 'system.collection.generic.dictionary(of string, string)'
Solution
Helps to put the () on the end an array. :P
The conventional way is:
Dim both = New List(Of Dictionary(Of String, String))()
both.Add(Dictionary1)
both.Add(Dictionary2)
The error says it all. You are trying to add an array of dictionaries to the list, but the add method only takes a single dictionary, not an array of them. Either fix it so you are only passing in a single dictionary:
Dim myDictionary As Dictionary(Of String, String)
' ...
listOfDictionaries.Add(myDictionary)
Or use the AddRange method to add all the dictionaries in the array at once:
Dim myArrayOfDictionaries() As Dictionary(Of String, String)
' ...
listOfDictionaries.AddRange(myArrayOfDictionaries)
I tend to favour single-line solutions when it's something straightforward like this, making use of the From keyword.
Dim listOfDictionaries = New List(Of Dictionary(Of String, String)) From { dictionary1, dictionary2 }

Compile error while adding items to nested dictionary

I am trying to created nested dictionary variable like the below, But I get compile error stating that it needs "}" at line where I am adding items (line #2) to my nested dictionary.
What Am I missing here? Thanks.
Dim myNestedDictionary As Dictionary(Of String, Dictionary(Of String, Integer)) = New Dictionary(Of String, Dictionary(Of String, Integer))()
myNestedDictionary.Add("A", New Dictionary("A", 4)())
In VS 2008 and .net 3.5 you cannot declare and initialize a Dictionary in one line, so you have to do:
Dim myNestedDictionary As New Dictionary(Of String, Dictionary(Of String, Integer))()
Dim lTempDict As New Dictionary(Of String, Integer)
lTempDict.Add("A", 4)
myNestedDictionary.Add("A", lTempDict)
To retrieve the an item use the following:
Dim lDictionaryForA As Dictionary(Of String, Integer) = myNestedDictionary.Item("A")
Dim lValueForA As Integer = lDictionaryForA.Item("A")
The value in lValueForA should be 4.
You need to specify the type of dictionary you are creating when you add the records:
myNestedDictionary.Add("A", New Dictionary(Of String, Integer))
or otherwise pass an existing Dictionary(Of String, Integer) as the inside-dictionary argument (when adding key/value pairs to the external dictionary).
(BTW, Your external dictionary is a dictionary who's Keys are Strings and Values are Dictionaries (Of String, Integer), is this really what you wanted?)
In C# you can do that:
var myNestedDictionary = new Dictionary<string, Dictionary<string, int>>() {{ "A", new Dictionary<string, int>() { { "A", 4 } } }};
You can do it in VB 2010 as well, using the From keyword, but it doesn't compile in VS 2008. It will compile in VB 2010, no matter which .NET Framework you target. I've tried 2.0, 3.5 and 4.0.
Dim myNestedDictionary = New Dictionary(Of String, Dictionary(Of String, Integer))() From {{"A", New Dictionary(Of String, Integer) From {{"A", 4}}}}