2

I am using Firebase for Unity to store some Users with a score. Firebase returns my list of Users as a IDictionary<string, object> where the Key is some id generated by Firebase and the Value is another IDictionary<string, object> that represents the User.

The User has a Key called "score" and I want to sort all the Users by the Value of the score for a Leaderboard.

This more or less what the data would look like as JSON:

"users": {
  "<userid>" : {
    "name" : "John",
    "score": 5
    ...  
  },
  "<userid>" : {
    "name" : "Pete",
    "score" : 10
  }
  ... 
}

How would I go about sorting the list of users? I assume that I would need to use Linq in some way, but I am still struggling to grasp how it works.

Some help would really be appreciated. Thanks!

Donderbos
  • 155
  • 1
  • 8
  • You can't sort a `IDictionary`. They don't have a defined sort order. That's why `SortedDictionary` exists. Unless you're happy to have `IEnumerable>` then you can't get what you want. – Enigmativity Feb 18 '16 at 10:37
  • `Dictionary` can't be sorted, use `List` instead. – Alexander Derck Feb 18 '16 at 10:38
  • Look at [this](http://stackoverflow.com/questions/289/how-do-you-sort-a-dictionary-by-value) – Neyoh Feb 18 '16 at 10:46
  • are you looking for really sorting the dictionary or just display them as in particular order? – Helic Feb 18 '16 at 10:55

4 Answers4

1

Given:

IDictionary<string, object> dict = new Dictionary<string, object>() {
    { "1", new Dictionary<string, object>() 
        {
            { "name", "John" },
            { "score", 5 }
        }
    },
    { "2", new Dictionary<string, object>() 
        {
            { "name", "Pete" },
            { "score", 4 }
        }
    },
};

You can:

var ordered = dict.OrderBy(x => (int)((IDictionary<string, object>)x.Value)["score"]).ToArray();

It is quite ugly, and if the score is missing then you'll get an exception.

If the score could be missing:

public static TValue GetValueOrDefault<TKey, TValue>(IDictionary<TKey, TValue> dict, TKey key)
{
    TValue value;
    dict.TryGetValue(key, out value);
    return value;
}

and then

var ordered = dict.OrderBy(x => (int?)GetValueOrDefault((IDictionary<string, object>)x.Value, "score")).ToArray();
xanatos
  • 109,618
  • 12
  • 197
  • 280
0
IEnumerable<User> OrderByScore(IDictionary<string,object> firebaseList)
{
    return from user in firebaseList.Values.Cast<IDictionary<string,object>>()
        let name  = (string) user["name"]
        let score = int.Parse(user["score"].ToString())
        orderby score descending
        select new User { Name = name, Score = score};
}

class User
{
    public string Name  {get;set;}
    public int    Score {get;set;}
}
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
0

The other comments and answers focus on filtering the users client-side. This answer is about using Firebase's built-in query capabilities to filter data on the server, which unfortunately is not yet available in the Unity library.

From this post on the firebase-talk Google Group:

Right now, the [Firebase library for Unity] only supports a subset of the features you will find on the full platform. The way the unity sdk works is that it uses interop against the full sdk. So those methods are there, they are just not exposed.

We do accept pull requests. [If you're interested in contributing], look at:

it might give you enough of an idea to add the extra methods.

Supporting the desktop player (being able to hit play) is a bit more complicated, but enabling queries for iOS and Android should not be terribly complicated.

The topic is still quite fresh, so if you have additional questions I'd recommend you post them there.

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
0
const string scoreKey = "score";
const string nameKey = "name";
var highscores = userDict
                .OrderByDescending(u => ((IDictionary<string, object>)u.Value)[scoreKey])
                .Select(u => new {
                        Name = ((IDictionary<string, object>)u.Value)[nameKey], 
                        Score = ((IDictionary<string, object>)u.Value)[scoreKey]
                    }
                 );

Fiddle

Georg Patscheider
  • 9,357
  • 1
  • 26
  • 36