-2

How do you sort a generic dictionary(string,float) in descending order by value without using Linq, using only features available in .net 2.0.

Just a note that I am not looking to sort the values by themselves - the key needs to somehow be connected to the value. (Otherwise, I would be asking for how to sort a list, right?)

ina
  • 19,167
  • 39
  • 122
  • 201
  • Soooooo, you do realize it doesn't make any sense to sort a dictionary? I am guessing in the end you want a sorted array of float maybe? – TheGeneral Oct 27 '18 at 01:40
  • please show what you've got so far – Rufus L Oct 27 '18 at 01:41
  • Maybe you could get inspired by the `Linq.OrderBy()` [implementation in the .Net source code](https://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,2566) for the method (follow the code flow a bit downwards. It's the QuickSort part). – Jimi Oct 27 '18 at 02:12
  • 1
    @ina Are you trying to sort the dictionary in place? Or take the contents of the dictionary into a new object / data structure that is stored? _I ask since the former is not possible, the latter is possible._ – mjwills Oct 27 '18 at 02:17
  • Surprisingly even .NET 2.0 had "SortedDictionary", which would allow using a custom comparator on the *key* (but not the value) to have the entries sorted in descending order, and it does also have OrderedDictionary, a non-generic type that allows insert the pairs in whatever order you like, but I don't see a nice generic solution that allows sorting by value (which does seem a rather odd thing to want to do) – Dylan Nicholson Oct 27 '18 at 02:41
  • @mjwills the former... so you're saying i would need a new dictionary object with the sorted floats? – ina Oct 27 '18 at 23:34
  • @ina No I am saying you are asking `Dictionary` to do something that it explicitly says it doesn't promise to do. https://stackoverflow.com/a/4007787 Can you do this with `Dictionary`? The answer is no. – mjwills Oct 28 '18 at 01:02

2 Answers2

1

If you just want a sorted array of float, this is .net 2 compliant

var dict = new Dictionary<string,float>();
var values = new float[dict.Count];
dict.Values.CopyTo(values, 0);
Array.Sort(values);
Array.Reverse(values);

Or

private class SortDesc : IComparer
{
   int IComparer.Compare(object a, object b)
   {
      var c1 = (KeyValuePair<string, float>)a;
      var c2 = (KeyValuePair<string, float>)b;
      if (c1.Value > c2.Value)
         return -1;
      return c1.Value < c2.Value ? 1 : 0;
   }
}

Usage

var dict = new Dictionary<string, float>();
var result = new KeyValuePair<string, float>[dict.Count];
((ICollection<KeyValuePair<string, float>>)dict).CopyTo(result, 0);

var sortDesc = new SortDesc();      
Array.Sort(result, sortDesc);

Disclaimer : Totally untested

I feel its my duty to note, .Net 2.0 is no longer supported and is no longer shipped

enter image description here

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
0

using only features available in .net 2.0

Assuming you have installed the multi-target packages for Visual Studio, you should be able to target a specific framework when you create a project. You can also change the targeted framework via the project's property pages.

FrameWork Selection

If you also need to specify the supported language version, this can be set via the project properties Build Tab by clicking on the "Advanced" button. In this case, ISO-2 is selected to correspond to C# V2 that was released as part of VS2005 along with .Net 2.0.

Language Version Selection

If you need information on multi-targeting, see:

With the project environment thus configured, you will only be able to use features available in .Net 2.0 and C# 2.0. This includes what you will see in the Object Browser.

Now to the issue at hand, sorting the Dictionary<string, float> contents by Value.

A simple way is to extract out the key-value pairs into a class supports sorting. The example below uses a List<KeyValuePair<string, float>> to hold the values. The list's sort method is passed a System.Comparison delegate to the that method defines the comparison logic. The comparison logic is designed to sort by both value (descending) and secondarily on key (ascending) if the values are equal.

public void Test()
{
    Dictionary<string, float> dict = new Dictionary<string, float>();
    dict.Add("A1", 3);
    dict.Add("A2", 30);
    dict.Add("Z", 30);
    dict.Add("A3", 30);
    dict.Add("F", 5);

    List<KeyValuePair<string, float>> sorted = new List<KeyValuePair<string, float>>(dict);
    sorted.Sort(new Comparison<KeyValuePair<string, float>>(CompareKvp));
    foreach(KeyValuePair<string, float> kvp in sorted)
    {
        Console.WriteLine(kvp.ToString());
    }
}

private static Int32 CompareKvp(KeyValuePair<string, float> kvp1, KeyValuePair<string, float> kvp2)
{
    int ret = - kvp1.Value.CompareTo(kvp2.Value); // negate for descending
    if (ret == 0)
    {
        ret = kvp1.Key.CompareTo(kvp2.Key); // Ascend comp for Key
    }
    return ret; 
}

This example will yield ordered key-value pairs:

[A2, 30]
[A3, 30]
[Z, 30]
[F, 5]
[A1, 3]
TnTinMn
  • 11,522
  • 3
  • 18
  • 39
  • Another way to test .net 2 support - grab Unity https://unity3d.com/get-unity/download/archive – ina Oct 27 '18 at 23:41
  • Okay, so my silly question is now... did the dictionary turn into a list? why not keep it a dictionary? – ina Oct 27 '18 at 23:42
  • The [Dictionary Class](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netframework-4.7.2) implements several interfaces; one of which is `IEnumerable>`. One of the ]constructors for List](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.-ctor?view=netframework-4.7.2#System_Collections_Generic_List_1__ctor_System_Collections_Generic_IEnumerable__0__() accepts an IEnumerable as a list source. – TnTinMn Oct 28 '18 at 00:08
  • "why not keep it a dictionary?" - The dictionary itself does not support sorting, hence your original question. LINQ is just a set of methods that works with IEnumerable's as a item source. I chose a `List` because it includes a Sort method. – TnTinMn Oct 28 '18 at 00:14
  • hmm okay, so is there a better way to return a dictionary than to create a new dictionary and just populate it where it says `console.writeline` in your last `foreach`? the goal is to be able to access the values by key easily. – ina Oct 28 '18 at 00:27
  • Your question is about sorting a Dictionary's contents. The example I posted is one that I thought must people would understand (I guess I failed in that) where it creates an example dictionary, shows a method of sorting its contents and then demonstrates that the contents are sorted by writing them out in the foreach loop. The original dictionary is not altered, but that is somewhat implied by your question stating the use of LINQ to perform sorting. If my solution or the other valid technique posted by TheGeneral do not meet your needs, perhaps you should work on rephrasing your question. – TnTinMn Oct 28 '18 at 00:47