Sorting custom class dictionary C#
Asked Answered
S

2

-1

I have a nested public class KeyCountMap

public KeyCountMap<T>  
{ 
   private IDictionary<T, MutableInt> map = new Dictionary<T, MutableInt>();
   public KeyCountMap()
   { }

   public KeyCountMap(Type dictionaryType)
   {
      if (!typeof(IDictionary<T, MutableInt>).IsAssignableFrom(dictionaryType))
      {
         throw new ArgumentException("Type must be a IDictionary<T, MutableInt>", "dictionaryType");
      }
      map = (IDictionary<T, MutableInt>)Activator.CreateInstance(_dictionaryType);
   }  

   public HashSet<KeyValuePair<T, MutableInt>> EntrySet()
   {
      return map.ToSet();
   }  
   //... rest of the methods...
}

To sort out the values in map in descending order of values, if we use Java we can write method as:

public static <T> KeyCountMap<T> sortMapByDescendValue(KeyCountMap<T> map) 
{
   List<Entry<T, MutableInt>> list = new LinkedList<>(map.entrySet());
   Collections.sort(list, new Comparator<Entry<T, MutableInt>>() 
   {
      @Override
      public int compare(Entry<T, MutableInt> o1, Entry<T, MutableInt> o2)  
      {
         return (-1) * (o1.getValue().get()).compareTo(o2.getValue().get());
      }
   });

   KeyCountMap<T> result = new KeyCountMap<T>();
   for (Entry<T, MutableInt> entry : list) 
   {
      result.put(entry.getKey(), entry.getValue());
   }
   return result;
}

If we use C#, we can defined method as:

public static KeyCountMap<T> SortMapByDescendValue<T>(KeyCountMap<T> map)
{
   List<KeyValuePair<T, MutableInt>> list = new List<KeyValuePair<T, MutableInt>>(map.EntrySet());  
   // map.EntrySet() returns of type HashSet<KeyValuePair<T, MutableInt>>  

   list = list.OrderByDescending(x => x.Value).ToList();

   KeyCountMap<T> result = new KeyCountMap<T>();
   foreach (KeyValuePair<T, MutableInt> entry in list)
   {
      result.Put(entry.Key, entry.Value);

   }
   return result; 
}

Will this method work or is it necessary to override CompareTo() method (not used here) for sorting?

EDIT

public class MutableInt
{
   internal int _value = 1; // note that we start at 1 since we're counting

   public void Increment()
   {
      _value++;
   }

   public void Discrement()
   {
      _value--;
   }

   public int Get()
   {
      return _value;
   }
}
Savage answered 14/6, 2016 at 11:58 Comment(12)
Dictionaries aren't guaranteed to return items in the order in which they were inserted, so what you're trying to do there probably won't work.Alexandrina
So how to sort out this problem i.e. sorting a dictionary ?Savage
Please, have a look at SortedDictionary<K,V>Clarkia
I have IDictionary not a SortedDictionary in class KeyCountMap<T>Savage
@DmitryBychenko If I use SortedDictionary instead of IDictionary in class KeyCountMap<T> then is there any need to write a method like that SortMapByDescendValue() ?Savage
@Taufel: yes, you have to provide a comparer: msdn.microsoft.com/en-us/library/a045f865(v=vs.110).aspxClarkia
@DmitryBychenko moreover I have to sort by value instead of sort by key, as you suggested SortedDictionary it allows you to avoid sorting keysSavage
@Taufel: yes, you have to compare pairs given by keys, but since you have both keys, you can obtain values compare them and return +1, -1, 0Clarkia
I have to provide a Comparer but what about sorting by value?Savage
How will you modify my C# version of method above using Comparer?Savage
@DmitryBychenko Do I need to override any method or all is this simply done inside that method ? Please demonstrate your suggestion via an answerSavage
@Taufel, again, what is the purpose behind all this? After seeing this question and the previous question, I see you're taking the line-by-line translation approach. What are you trying to achieve? Why don't you use a SortedDictionary<,>, or a list if insertion order matters? Why MutableInt? If you provide a context, you'll most probably obtain better answers. As things are now, it seems you're trying to refurbish Java code to C# for no reason.Burl
U
2

Dictionaries (hashtables) don't have an order. Trying to order a hashset by controlling the order of insertion just won't work. If you want ordering, don't use a dictionary as your backing store.

Unhallow answered 14/6, 2016 at 12:6 Comment(4)
Have a look at the SortedSet (msdn.microsoft.com/en-us/library/dd412070(v=vs.110).aspx).Onslaught
@Taufel Well, what do you need? You need a Dictionary, use one. You need a List, use one. I suggest you read up about the differences between the two. A dictionary is not a list.Scholium
If you see, the input parameter to the method SortMapByDescendValue() is of type KeyCountMap<T> whereas the sorting is being done using a List, so the issue is parameter of type KeyCountMap<T> which is a class using DictionarySavage
@ThorstenDittmar My question is something else, if you read my comment here and .CompareTo overriding in the question i.e. as if we use this just like Collections.sort(list, new Comparator<Entry<T, MutableInt>>() this in javaSavage
C
0

If you want permanently sorted dictionary, you can try implementing sorting with SortedDictionary<K,V>:

  // Please, notice ...map => new... (C# 6.0 syntax) 
  // since you can't address map in the initializator (=)
  private IDictionary<T, MutableInt> map => new SortedDictionary<T, MutableInt>(
    // You are supposed to compare keys
    Comparer<T>.Create((leftKey, rightKey) => {
      // given keys, get values
      MutableInt left = map[leftKey]; 
      MutableInt right = map[rightKey];  

      //TODO: you may want to change logic here
      // you should return any positive integer if left > right
      // negative integer if left < right
      // zero in case left == right
      // current implementation (CompareTo) assumes that 
      // MutableInt implements IComparable<MutableInt> interface
      return -left.CompareTo(right);
    })
  );

EDIT: if you want to represent dictionary ordered by value, the best way is IMHO to make values comparable

public class MutableInt: IComparable<MutableInt> 
{
  ...
  public int CompareTo(MutableInt other) 
  {
    return (null == other)
      ? 1
      : _value.CompareTo(other._value);      
  } 
  ...
}

And then use Linq:

//Notice, that you can't return sorted values as dictionary
public static IEnumerable<KeyValuePair<T, MutableInt>> SortMapByDescendValue<T>(
  KeyCountMap<T> map)
{
   return map
     .OrderByDescending(pair => pair.Value); // Value is comparable now
}

The only thing you can't do is to sort standard dictionary (Dictionary<K, V>)

Clarkia answered 14/6, 2016 at 13:17 Comment(7)
For your notice here MutableInt is user-defined class updated aboveSavage
@Taufel: I see; I've supposed that MutableInt is some kind of integer and that's why is comparable to each other, in other words MutableInt implements IComparable<MutableInt>Clarkia
But its not getable for me that what you have given in your answer, is this a method in place of SortMapByDescendValue() or what else it is ?Savage
@Taufel: OK now, could you, please, clarify, what are you looking for? A dictionary that permanently sorted (my current answer) or how to represent (print out etc) a standard dictionary content with values sorted in some order?Clarkia
I am looking for: to give an object of type KeyCountMap<T> to the method that is doing sorting and return a KeyCountMap<T> type that is sorted by value descend, and what the object of KeyCountMap<T> will contain, you can see KeyCountMap<T> class given aboveSavage
But where else have you used .CompareTo() method defined in this class MutableInt?Savage
By the way I also have used _list = _list.OrderByDescending(_x => _x.Value).ToList(); in my method definitionSavage

© 2022 - 2024 — McMap. All rights reserved.