简体   繁体   中英

Sorting a list of dictionaries based on a key

I have a list of dictionaries which contains student data It is something like

List<Dictionary<string, object>> students = new List<Dictionary<string, object>>();
Dictionary<string, object> std1 = new Dictionary<string, object>();
std1["name"] = "sai";
std1["age"] = 22;
std1["gender"] = "male";
students.Add(std1);

Dictionary<string, object> std2 = new Dictionary<string, object>();
std2["name"] = "Julia";
std2["gender"] = "female";
students.Add(std2);

Dictionary<string, object> std3 = new Dictionary<string, object>();
std3 ["name"] = "sunny";
std3 ["age"] = 23;
students.Add(std3);  

And I want to sort the list of students based on either name , age or gender , I am trying something like this:

var ordered = students.OrderBy(x => x["name"]);

If I try with either age or gender it is returning an error that key is not found, as std2 doesn't have age and std3 doesn't have gender .

I need all the records even it doesn't contain the value for sorted key, Any way to solve this problem, Thanks in advance.

It is better to create a class like this:

public class YourClass
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
}

Then:

List<YourClass> students = new List<YourClass>();
YourClass std1 = new YourClass();
std1.Name = "sai";
std1.Age = 22;
std1.Gender = "male";
students.Add(std1);

yourClass std2 = new yourClass();
std2.Name = "Julia";
std2.Gender = "female";
students.Add(std2);

yourClass std3 = new yourClass();
std3.Name = "sunny";
std3.Age = 23;
students.Add(std3);

var ordered = students.OrderBy(x => x.Name);

This arrangement stores the same data you had in multiple dictionaries. However, it's far more clear and understandable.

If you want to sort by a key that is not present in all of the dictionaries, you'll need to return a default value instead, for example 0.

var ordered = students.OrderBy(dict =>
{
    string name;
    if (!dict.TryGetValue("name", out name))
        return "";
    return name;
});

Shorter version using the conditional ternary operator:

var ordered = students.OrderBy(dict =>
{
    string name;
    return dict.TryGetValue("name", out name) ? name : 0;
});

I use Dictionary.TryGetValue(...) which returns a bool depicting whether the key was found in the dictionary and its value returned.

You can solve this problem by supplying a GetOptional method that returns some default object in situations when the dictionary does not have a specific key:

V GetOptional<K,V>(IDictionary<K,V> d, K key, V absent) {
    V res;
    return d.TryGetValue(key, out res) ? res : absent;
}

Now you can sort like this:

var byName = students.OrderBy(x => GetOptional<string,object>(x, "name", "----"));
var byAge = students.OrderBy(x => GetOptional<string,object>(x, "age", "10000"));

Note: Using dictionaries like this gives you flexibility at the expense of clarity. It is usually better to define a special Student type, rather than using a universal collection of key-value pairs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM