Sorting a dictionary<key, value>

Hi all, so im making a turn based rpg and in the combat system ive run into a bit of a problem and need help with 2 things. So im trying to make a battle order based on the speed of a unit. So i made a dictionary to get all the speeds of all the units which populates without a problem. The dictionary is of type <Unit, int> and i populate it so the dictionary looks something like this

{
unit0, 8
unit1, 3
unit2, 6
unit3,10
}

the first thing im having trouble with is sorting it by the int value so it turns out like this

{
unit3, 10
unit0, 8
unit2, 6
unit1, 3
}

then the second problem i have is inserting that in order into my turn dictionary which idk if it should take in
<int, dictionary<Unit,int>> or simply <int, Unit>. Basically the goal is to have a dictionary end up looking like this with the int representing the battle order.

{
0, unit3
1, unit0
2, unit2
3, unit1
}

Again im not sure how to sort the first dictionary, then take that order and populate another dictionary so the order stays the same. I appreciate any and all help. Thank you!

Dictionaries are not an ordered data structure. There isn’t really a concept of the Dictionary being in any particular order.

You could create a secondary list that represents the turn order:

List<Unit> turnOrder = turnOrderDict.Values.OrderBy(unit => turnOrderDict[unit]).ToList();

You can also use a SortedDictionary<int, Unit>. But you won’t be able to query that dictionary by the Unit, only by the turn order (SortedDictionary is ordered by the key).

1 Like

Thanks for the quick response! However, i dont think thatll work for me. Heres some exact code

    private IEnumerator StartBattle()
    {
        InstantiateBattleUnits();

        yield return new WaitForSeconds(2f);

        SetUnitSpeeds();

        yield return new WaitForSeconds(1f);

        SetUnitOrder();

        SetUnitStartTransforms();
    }

private void SetUnitSpeeds()
    {
        battleUnits = FindObjectsOfType<BattleUnit>();
        if (!hasSetSpeeds)
        {
            if (speedsDictionary.Count != battleUnits.Length)
            {
                foreach (BattleUnit unitToTest in battleUnits)
                {               
                    speedsDictionary.Add(unitToTest, unitToTest.GetSpeed());
                }
            }
            else
            {
                hasSetSpeeds = true;
            }           
        }           
    }

    private void SetUnitOrder()
    {   
        foreach(BattleUnit unitToSet in battleUnits)
        {
            //this is where im trying to implement your solution
        }
    }

Sort the battleUnits list itself, using a lambda comparer. The Dictionary is a completely unnecessary part of this. Should look something like this:

battleUnits.Sort( (a, b) => a.GetSpeed().CompareTo(b.GetSpeed()) );

Basically this tells the sort function, “here’s a small bit of code that can tell you how to sort two of these objects relative to each other”, which in this case is comparing their two GetSpeed() values.

I don’t know what GetSpeed() does but if you’re sorting a bunch of units, make sure that it’s very fast. (If calculations are necessary to get their speed, you may need to cache its return value.) The lambda function there will get called every time two objects are compared to each other while sorting, which happens a LOT of times for large lists.

3 Likes

Thank you so much, works almost perfectly, just backwards lol! just switched

battleUnits.Sort( (a, b) => a.GetSpeed().CompareTo(b.GetSpeed()) );

to

battleUnits.Sort( (a, b) => b.GetSpeed().CompareTo(a.GetSpeed()) );

and seems to be working perfectly, thank you so much!

Hi! The function you gave me was working great in my battle, however, as i made it to the point were i added more people, it seems to have stopped working. Is there any possibility this wouldnt work with a list 10 units long? Im getting a “object reference not set to an instance of an object.” I assume your function works and its a problem in my code, but i havent seemed to find it so wanted to cover all bases. Thanks again!

Sounds like you have some null references in your list.

1 Like