I have found this documentation (Enumerable.OrderBy(Of TSource, TKey) Method (IEnumerable(Of TSource), Func(Of TSource, TKey))
), where it says:
This method performs a stable sort; that is, if the keys of two elements are equal, the order of the elements is preserved. In contrast, an unstable sort does not preserve the order of elements that have the same key.
However, I do not have any idea about the difference between stable and unstable sort (?).
Let's say that I have a public property, an array, called fields
(as clsField()
) where a parser
has placed all the objects...
Public Class clsField
Public idx As String
Public name As String
Public order As Long
End Class
Public Class Container
Public fields As clsField()
Public Function getFields() As Dictionary(Of String, clsField)
If (fields Is Nothing) OrElse (fields.Count < 1) Then Return New Dictionary(Of String, clsField)
Return fields.OrderBy(Function(fld) fld.order).ToDictionary(Of String, clsField)(Function(fld) fld.idx, Function(fld) fld)
End Function
Public Function getFields(blnAlternative As Boolean) As Dictionary(Of String, clsField)
If (fields Is Nothing) OrElse (fields.Count < 1) Then Return New Dictionary(Of String, clsField)
Return fields.ToDictionary(Of String, clsField)(Function(fld) fld.idx, Function(fld) fld).OrderBy(Function(pair) pair.Value.order)
End Function
End Class
Public Class Consumer
Public cont As Container
Public parse As Parser
Public Sub New(strFormat)
cont = New Container
cont.fields = parse.deserializeOject(Of clsField())(strFormat)
End Sub
Public Sub printFields_Sort_Dic()
For Each fld As clsField In cont.getFields().Values
Console.WriteLine(fld.ToString)
Next
End Sub
Public Sub printFields_Dic_Sort()
For Each fld As clsField In cont.getFields(True).Values
Console.WriteLine(fld.ToString)
Next
End Sub
Public Sub Main()
printFields_Dic_Sort()
printFields_Sort_Dic()
End Sub
End Class
Two doubts related to the above code:
- Will the order in which the
Parser
has inserted the elements into the arrayfields
be preserved for elements with sameorder
? - Could
printFields_Dic_Sort()
have different order thanprintFields_Sort_Dic()
? (the first converts and then sorts; second sorts and then converts intoDictionary
)
Could not join definitive information on this... Thanks
EDITED
Added types for returned Dictionary
Ok, this is the problem:
- If I want to have
KeyValuePair
(idx, obj) cannot use anarray
(wrong: it is possible; the challenge is how to convert between arrays) - I cannot store the sorted
array
in aDictionary
because there is not guarantee that iterating through it will give orderedvalues
(right: no guarantee with generic Dictionary, see below) . - There is the option to use
SortedDictionary
. However, there is no direct conversion fromarray
toSortedDictionary
(unless you do the iteration)... (**right*?*: no trivial conversion betweenarray
/list
andSortedDictionary
) - Then, for an easy and quick solution it only remains the use of
list
. However, there there are problems as well, because it should be a list ofKeyValuePair
that I cannot get directly from thearray
by the use oftoList
(wrong: it is possible to get theList (Of KeyValuePair (Of ...))
, however, it requires a previous conversion).
So no elegant (short and simple) solution at all... (right: no comments)
Any help will be highly appreciated (still working with it) - Solved below...
EDIT II
Ok, this what I finally have done: solve the problem at point 4 by using array.ConvertAll
(msdn) and defining my own Converter
function... to convert the array
and then, get a List
, by ToList
, from that intermediate array
that already has the type converted to (Of KeyValuePair (Of String, clsFld))
. Hope it helps someone else:
'Imports System.Linq.Enumerable
'Imports System.Runtime.CompilerServices ' for extensions
Public Class clsField
Public idx As String
Public name As String
Public weight As Long
Public Sub New(Optional i As String = vbNullString, Optional n As String = vbNullString, Optional w As Long = vbNullString)
idx = i : name = n : weight = w
End Sub
End Class
Public Class Container
Public fields As clsField()
' returns a list sorted by clsField.weight preserving order for elements with same 'weight' value
Public Function getFields() As List(Of KeyValuePair(Of String, clsField))
Dim auxList As List(Of KeyValuePair(Of String, clsField))
If (fields Is Nothing) OrElse (fields.Count < 1) Then Return New List(Of KeyValuePair(Of String, clsField))
' .ToList to transform IEnumerable to the return type
auxList = Array.ConvertAll(fields, New Converter(Of clsField, KeyValuePair(Of String, clsField))(AddressOf FieldToPair)).ToList
Return auxList.OrderBy(Function(x) x.Value.weight).ToList()
End Function
Public Shared Function FieldToPair(fld As clsField) As KeyValuePair(Of String, clsField)
Return New KeyValuePair(Of String, clsField)(fld.idx, fld)
End Function
End Class
Public Class Consumer
Public cont As Container
Public Sub New()
cont = New Container
cont.fields.Add(New clsField("ffq", "foo30004", 33))
cont.fields.Add(New clsField("ffc", "foo9997", 55))
cont.fields.Add(New clsField("ffp", "foo9908", 55))
cont.fields.Add(New clsField("ffo", "foo100001", 22))
cont.fields.Add(New clsField("ffx", "foo8885", 33))
cont.fields.Add(New clsField("ffz", "foo70002", 22))
cont.fields.Add(New clsField("ffy", "foo8806", 33))
cont.fields.Add(New clsField("ffa", "foo9009", 55))
cont.fields.Add(New clsField("ffb", "foo8000", 55))
cont.fields.Add(New clsField("ffn", "foo7003", 22))
End Sub
Public Sub printSortedFields()
Dim aux As List(Of KeyValuePair(Of String, clsField))
aux = cont.getFields()
For Each pair As KeyValuePair(Of String, clsField) In aux
Console.WriteLine(pair.Value.name)
With pair.Value
Debug.Print("name: " & .name & " || idx: " & .idx & " || weight: " & .weight)
End With
Next
End Sub
Public Sub Main()
printSortedFields()
End Sub
End Class
Module ArrayExtension ' custom method for array
<Extension()>
Public Sub Add(Of T)(ByRef arr As T(), item As T)
If arr IsNot Nothing Then
Array.Resize(arr, arr.Length + 1)
arr(arr.Length - 1) = item
Else
ReDim arr(0)
arr(0) = item
End If
End Sub
End Module
Result for the test above:
name: foo100001 || idx: ffo || weight: 22
name: foo70002 || idx: ffz || weight: 22
name: foo7003 || idx: ffn || weight: 22
name: foo30004 || idx: ffq || weight: 33
name: foo8885 || idx: ffx || weight: 33
name: foo8806 || idx: ffy || weight: 33
name: foo9997 || idx: ffc || weight: 55
name: foo9908 || idx: ffp || weight: 55
name: foo9009 || idx: ffa || weight: 55
name: foo8000 || idx: ffb || weight: 55