简体   繁体   中英

How to sort a dictionary by key, if key is a list (in C#)?

I have a dictionary (using C#):

Dictionary<List<string>, string> dictData = new Dictionary<List<string>, string>();

where the dictionary already has a values (for example):

key: {"3", "1", "45"}, value: "test value 1"
key: {"1", "2", "45"}, value: "test value 2"
key: {"11", "1", "45"}, value: "test value 3"
key: {"1", "1", "45"}, value: "test value 4"

the key is a list of strings and it will always have at least two elements. What I need to do is to do a sorting of the dictionary by the key, or to be more precise, to sort by the first element of the list, and as a second criteria to sort by second element of the list. The strings are actually a numbers, so they should be sorted as numbers ("3" should be smaller than "11"). So for the example above, I should get the following result:

key: {"1", "1", "45"}, value: "test value 4"
key: {"1", "2", "45"}, value: "test value 2"
key: {"3", "1", "45"}, value: "test value 1"
key: {"11", "1", "45"}, value: "test value 3"

again: how can I sort the dictionary by the key, if the key is actually a list and the sorting to be performed by the first element of the list, and then by the second element of the list?

If you have two List<int> containing: 1, 2, 5 and 1, 2, 5, then those two lists are not the same list . They are separate list instances that both happen to contain the same values in the same order because lists (like other collection types including arrays) are reference types . You can't use them as a unique key because the dictionary will treat them as different keys.

I would suggest creating a struct that contains your three values and using that as the key. The reason is because a struct is a value type , and two instances that have the same property values will be treated as equal, which is what you need for a dictionary key.

struct Values
{
    public int First { get; set; }
    public int Second { get; set; }
    public int Third { get; set; }
}

Then you can do this:

var x = new Dictionary<Values, string>()
    {
        {new Values() {First = 1, Second = 1, Third = 45}, "test value 1"},
        {new Values() {First = 1, Second = 2, Third = 45}, "test value 2"},
        {new Values() {First = 11, Second = 1, Third = 45}, "test value 3"},
    };

var sorted = x.OrderBy(kvp => kvp.Key.First).Select(kvp => kvp.Value);

If you really need it to be as your current setup, this works (test code, it'll need to be adjusted). It's similar to original answer, it just does the full list (assuming max 3). Tested and seems to be working. You'll need to add logic for if it doesn't have all 3, etc. This is just a base setup to get you going:

private void DoIt()
    {
        Dictionary<List<string>, string> test = new Dictionary<List<string>, string>();
        List<string> workerList = new List<string>() { "3", "1", "45" };
        test.Add(workerList, "test value 1");
        workerList = new List<string>() { "1", "2", "45" };
        test.Add(workerList, "test value 2");
        workerList = new List<string>() { "11", "1", "45" };
        test.Add(workerList, "test value 3");
        workerList = new List<string>() { "1", "1", "45" };
        test.Add(workerList, "test value 4");


        foreach(KeyValuePair<List<string>,string> kvp in test.OrderBy(x => int.Parse(x.Key[0])).ThenBy(y => int.Parse(y.Key[1])).ThenBy(z => int.Parse(z.Key[2])))
        {
            Console.WriteLine("Key: " + kvp.Key[0].ToString() + "," + kvp.Key[1].ToString() + "," + kvp.Key[2].ToString() + " | " + "Value: " + kvp.Value.ToString());
        }
    }

outputs:

Key: 1,1,45 | Value: test value 4
Key: 1,2,45 | Value: test value 2
Key: 3,1,45 | Value: test value 1
Key: 11,1,45 | Value: test value 3

To use a list as a key for a Dictionary you can do something like this

public class DictionaryKeyList {

    public List<string> Lst { get; set; }

    public override bool Equals(Object otherObj){
        var otherList = otherObj as DictionaryKeyList;

        return !this.Lst.Zip(otherList, (a,b) => a == b).Any(x => !x);
    }

Then use a dictionary as type

Dictionary<DictionaryKeyList, string> dictData;

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