Ranking Dictionary by Value (int) ?

Hello !

I was wondering if it was possible to classify my dictionary by int value.
I would like to sort my key collection (which are music titles) in descending order of their respective value (int).
I have already created a list of music with their vote but I will like classified by this method in Update ():

Dictionary<string, int> voteCount;
....

foreach (string title in voteCount.Keys)
        {
            var item = GameObject.Find(title);
            item.GetComponentInChildren<Text>().text = title + " :    +" + voteCount[title].ToString();
         //Ranking with Keys ? And edited Component.text by descending order
        }

For example graphically, I will have my list of object (key) + their value (int value):
(michael jackson beat it) + 5
(Beyoncé - Halo) + 3
(Stromae - Papaoutai) + 2
(Sia - Never Give Up) + 2

What do you think, please? :slight_smile:

Pulsar,

Dictionary is an unsorted collection.

Since the keys are placed in buckets based on their hashcode. The placement is fully dependent on the hashcode. No sorting possible.

If you want a sortable dictionary, see SortedDictionary:

Do note that the insertion/retrieval speed is slower than Dictionary. Dictionary has an O(1) insertion/retrieval, where as SortedDictionary has a O(log n) insertion/retrieval. Though that is faster than SortedList’s O(n) insertion. (with the exception of pre-sorted data):

1 Like

Thank you for your answer @lordofduct !

I changed everything in SortedDictionary which seems to be a best solution.
But, I don’t see how I could specify the classification of my elements (according to the methods that I could read)… :sweat_smile:

This way can be correct too?
Now you have to find a way to create the gameobjects in the order of the result …:face_with_spiral_eyes:

 var result = voteCount.OrderByDescending(i => i.Value);
            foreach (KeyValuePair<string, int> kvp in result)
            {
                //Debug.Log(kvp.Key + kvp.Value);
                var item = GameObject.Find(kvp.Key);
                item.GetComponentInChildren<Text>().text = kvp.Key + " :    +" + kvp.Value;
            }

I’m assuming you mean define by what they’re sorted.

You do this by creating an IComparer:
https://msdn.microsoft.com/en-us/library/8ehhxeaf(v=vs.110).aspx

When you create the sorted dict you pass in the IComparer to its constructor:
https://msdn.microsoft.com/en-us/library/a045f865(v=vs.110).aspx

When ever it does an insertion it’ll use this to compare 2 objects to then select where it’ll be inserted.

Now what you’ll need to do is create a field that you use to compare by. So whatever type you use as a key should probably have this field defined on itself.

If you do this… do not use a SortedDict. You basically subverted the entire point of a SortedDict by instead sorting it every time you access it.

Which is also an option.

But don’t use the 2 in conjunction… since you take the cost of a SortedDict (the fact it has slow insertions/retrieves), but ignored its benefits (the sorted nature).

You can use this very same linq code on a regular Dictionary.

What is it you’re attempting to do?

Not what things you’re attempting to use to get it done. But your actual end goal. Why do you need this sorted? What are these GameObject’s you’re creating?

1 Like

Oops, I meant ‘’ I have to find ‘’ sorry ! Was sleeping…

I need to switch my gameobjects with best score (+1 in picture) in the top of my list Key-Value like that :
https://www.noelshack.com/2018-19-2-1525741421-capture.png
:frowning: So hard…

First things first, you can just upload images to the forums here and post them directly in. So that way you don’t have to link out to other sites. Or if you do link out… you can still embed them. Like so:

Now with that said.

Are these UI elements inside a parent container that uses the ‘VerticalLayoutGroup’:
https://docs.unity3d.com/Manual/script-VerticalLayoutGroup.html

super useful for this sort of stuff.

If so, then it’s just the child order that needs to be changed.

So you can do something like this… completely foregoing the entire dictionary thing.

First create a simple data container for each entry:

public class MusicEntryData : MonoBehaviour
{
   
    public int Score;
    public string Name;
   
    public Text text;
   
    void OnEnable()
    {
        this.MoveToScreen();
    }
   
    public void MoveToScreen()
    {
        text.text = string.Format("{0} :   +{1}", Name, Score);
    }
   
}

Then if you have the elements container, you can get the data entries, and you can use SetSiblingIndex to reorder. Since VerticalLayoutGroup uses the sibling index to order, this will update that:

Transform container = *the container holding elements*;

var arr = container.GetComponentsInChildren<MusicEntryData>();
System.Array.Sort(arr, (a, b) => a.Score.CompareTo(b.Score)); //you can flip a and b to sort the opposite direction
for(int i = 0; i < arr.Length; i++)
{
    arr[i].transform.SetSiblingIndex(i);
}
1 Like

It’s OK now :sunglasses:

Thank you very much @lordofduct !

[RESOLVED]