I'm working with a List of Dictionaries. I want to order each Dictionary inside the list by its values. I'm trying these two options:
1)
Dim myList As List(Of Dictionary(Of Integer, Single))
myList.ForEach(Function(x) x.OrderBy(Function(a) a.Value).ToDictionary(Function(y) y.Key, Function(y) y.Value))
2)
Dim myList As List(Of Dictionary(Of Integer, Single))
For Each element In myList
element = element.OrderBy(Function(a) a.Value).ToDictionary(Function(y) y.Key, Function(y) y.Value)
Next
However, none of these works. Can somebody help me?
Related
I have a list of objects within another list. It looks like this:
Dim _elements as List(Of List(Of Element))
_elements(0) is a list of Element1, Element2, etc.
_elements(1) is a list of Element5, Element6, etc.
I need to create a dictionary of the elements so that the index of each list is the Key in the dictionary. The value of the dictionary should hold all elements of the Legend type that can be found in the list. Something like the following:
Dim legendElements As New Dictionary(Of Integer, List(Of Element))
' Initialize the list in the dictionary
For i As Integer = 0 To _elements.Count - 1
legendElements(i) = new List(Of Element)
Next
For i As Integer = 0 To _elements.Count - 1
For each element as Element in _elements(i)
If element.GetType() Is GetType(Legend) Then
legendElements.add(element)
End If
Next
Next
Is there a System.Linq function that can do the equivalent as the example above?
Call Enumerable.SelectMany method to get a flatten list of the target type which you filter by calling the Enumerable.Where method. Call the Enumerable.Select method to create from the result IEnumerable of anonymous objects to hold and pass the Legend objects along with their indices, and finally, call the Enumerable.ToDictionary method to create
Dictionary(Of Integer, Element) from the anonymous objects.
Dim legendElements As Dictionary(Of Integer, Element) = elements.
SelectMany(Function(x) x.Where(Function(y) y.GetType Is GetType(Legend))).
Select(Function(v, k) New With {Key .Key = k, .Value = v}).
ToDictionary(Function(a) a.Key, Function(a) a.Value)
Do the proper cast if you need a Dictionary(Of Integer, Legend).
Dim legendElements As Dictionary(Of Integer, Legend) = elements.
SelectMany(Function(x) x.Where(Function(y) y.GetType Is GetType(Legend))).
Select(Function(v, k) New With {Key .Key = k, .Value = v}).
ToDictionary(Function(a) a.Key, Function(a) DirectCast(a.Value, Legend))
I have something like this:
Public Shared Property PinnedChannelConnectionIds() As Dictionary(Of Integer, List(Of String))
Get
If _pinnedChannelConnectionIds Is Nothing Then
Return New Dictionary(Of Integer, List(Of String))
Else
Return _pinnedChannelConnectionIds
End If
End Get
Set(value As Dictionary(Of Integer, List(Of String)))
_pinnedChannelConnectionIds = value
End Set
End Property
And then, have some data in dictionary as :
1, {"c1","c2", "c3"}
2, {"c2","c4", "c6"}
3, {"c3","c5", "c1"}
4, {"c4","c3", "c6"}
So to remove a specific item. Let say "c2" from the above dictionary.
I am doing like this:
For Each channelKeyValuePair As KeyValuePair(Of Integer, List(Of String)) In Channel.PinnedChannelConnectionIds
For Each item As String In channelKeyValuePair.Value.ToList()
If (item.Equals("c2")) Then
Channel.PinnedChannelConnectionIds(channelKeyValuePair.Key).Remove(item)
End If
Next
Next
But it throws error : Enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection.
Can anyone please help me out.
Thanks in advance!!
I'd suggest something like
For Each channelKeyValuePair As KeyValuePair(Of Integer, List(Of String)) In Channel.PinnedChannelConnectionIds
channelKeyValuePair.Value.RemoveAll(Function(x) x = "C2")
Next
might work. There's no need to iterate over the list elements to find and remove them and it can cause difficulties of the sort you are experiencing.
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)
I have a dictionary of String, Integer so the key is the string and the value is the integer and i want to order the keys ascending by the value of the integer. How could I achieve this?
You could use LINQ to sort the Dictionary by value:
Dim dictionary = New Dictionary(Of String, Integer)()
dictionary.Add("A", 2)
dictionary.Add("B", 4)
dictionary.Add("C", 5)
dictionary.Add("D", 3)
dictionary.Add("E", 1)
Dim sorted = From pair In dictionary
Order By pair.Value
Dim sortedDictionary = sorted.ToDictionary(Function(p) p.Key, Function(p) p.Value)
Actually it does not modify the original Dictionary but creates a new Dictionary with the new order.
But: Apart from the feasability, a Dictionary is not an IList (as an Array or List<T>). It's purpose is to lookup a key very efficiently but not to loop all entries.
They are unordered, meaning that although you can retrieve the elements in some order with a foreach loop, that order has no special meaning, and it might change for no apparent reason.
First of all, a dictionary does not have an intrinsic order. It is for look-ups. However, you can turn the keys into their own ordered list.
Dim keyList as List(Of String) = (From tPair As KeyValuePair(Of String, Integer) _
In myDictionary Order By tPair.Value Ascending _
Select tPair.Key).ToList
I had to do something similar to this with custom objects. I think this should be close (but may not be exactly) what you're looking for:
Dim sortedL As List(Of KeyValuePair(Of String, Integer)) = yourDictionary.ToList
sortedL.Sort(Function(firstPair As KeyValuePair(Of String, Integer), nextPair As KeyValuePair(Of String, Integer)) CInt(firstPair.Value).CompareTo(CInt(nextPair.Value)))
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.