简体   繁体   中英

Comparing List<KeyValuePair<>> in C#

I'm developing a program which needs to hold a list of scores and strings and I believe a List<KeyValuePair<int, List<string>>> would be the best list to use. I can't use a Dictionary as the keys are not unique so I use Insert and BinarySearch to keep the list sorted and I don't want to use List.Sort after each insert as I'm adding many items. ‌In my code I have:

private List<KeyValuePair<int, List<string>>> list;

List<string> values = new List<string>
{
    value1,
    value2,
    value3
};

// Insert values
list.Insert(index, new KeyValuePair<int, List<string>>(score, values));

// Find index of new position
int index = list.BinarySearch(new KeyValuePair<int, List<string>>(score, values), new Comparer());

private class Comparer : IComparer<KeyValuePair<int, List<string>>>
{
    public int Compare(
        KeyValuePair<int, List<string>> x,
        KeyValuePair<int, List<string>> y)
    {
        if ((x.Key == y.Key) && (x.Value[0] == y.Value[0]))
            return 0;
        if ((x.Key < y.Key) || ((x.Key == y.Key) && (x.Value[0] != y.Value[0])))
            return 1;

        return -1;
    }
}

'list' is maintained in descending score order and BinarySearch checks that the score and first value isn't already in the list or return its position in the list but I can't get Comparer to work. An example list would be:

23, Harry, Ottawa, Green 17, Amy, Venice, Red 17, Sue, Sydney, Blue 4, Harry, Durban, Blue

In this example 4, Harry, Miami, Red would be invalid as 4, Harry... already exists. Inserting 9, Dallas... would return 3 as the new position.

However I get the error CS0535 'Comparer' does not implement interface member 'IComparer<KeyValuePair<int, List<string>>>.Compare(KeyValuePair<int, List<string>>, KeyValuePair<int, List<string>>)' on the class. What am I doing wrong and how can I fix it?

This looks like the first element of the values has a special meaning.

The combination of the integer value along with that first element being unique, you can use a Dictionary having a tuple combining that integer and the first element of the list as key :

Try the below code yourself

// A SortedDictionary is like a Dictionary, but automatically sorted on the key
var dict = new SortedDictionary<(int, string), List<string>>();

var key = (23, "Harry");
// If you are using .NET Core 2.0 or above, you can use
/*
 * if (!dict.TryAdd(key, new List<string> { "Ottawa", "Green" }))
 *     Console.WriteLine($"Can't add {key}");
 */
if (!dict.ContainsKey(key))
    dict.Add(key, new List<string> { "Ottawa", "Green" });
else
    Console.WriteLine($"Can't add {key}");

key = (4, "Harry");
if (!dict.ContainsKey(key))
    dict.Add(key, new List<string> { "Durban", "Blue" });
else
    Console.WriteLine($"Can't add {key}");

key = (4, "Harry");
if (!dict.ContainsKey(key))
    dict.Add(key, new List<string> { "this is", "duplicate" });
else
    Console.WriteLine($"Can't add {key}");

key = (17, "Amy");
if (!dict.ContainsKey(key))
    dict.Add(key, new List<string> { "Venice", "Red" });
else
    Console.WriteLine($"Can't add {key}");

key = (17, "Sue");
if (!dict.ContainsKey(key))
    dict.Add(key, new List<string> { "Sydney", "Blue" });
else
    Console.WriteLine($"Can't add {key}");

Console.WriteLine("---------------------------------------");
Console.WriteLine("Notice now how sorted is the dictionary");
Console.WriteLine("---------------------------------------");
foreach (var Key in dict.Keys)
{
    Console.WriteLine($"dict[{Key}] Contains : ");
    foreach (var val in dict[Key])
    {
        Console.WriteLine($"\t{val}");
    }
}

This outputs :

Can't add (4, Harry)
---------------------------------------
Notice now how sorted is the dictionary
---------------------------------------
dict[(4, Harry)] Contains : 
    Durban
    Blue
dict[(17, Amy)] Contains : 
    Venice
    Red
dict[(17, Sue)] Contains : 
    Sydney
    Blue
dict[(23, Harry)] Contains : 
    Ottawa
    Green

Judging by the error message the new Comparer() in int index = list.BinarySearch(new KeyValuePair<int, List<string>>(score, values), new Comparer()); does not initialize your private class Comparer : IComparer<KeyValuePair<int, List<string>>> but the System.Collections.Comparer one.You should add the namespace to it like this: new YourNamespaceHere.Comparer()

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