Harry
Harry

Reputation: 15

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?

Upvotes: 0

Views: 291

Answers (2)

Cid
Cid

Reputation: 15247

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

Upvotes: 1

PeterL
PeterL

Reputation: 48

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()

Upvotes: 0

Related Questions