Arnab
Arnab

Reputation: 2354

Find index of a list of keyvalue pair by key -updated

I'm creating a list of key value pairs.

var myList = new List<KeyValuePair<string, int>>();
myList.Add(new KeyValuePair<string, int>("A", 1));
myList.Add(new KeyValuePair<string, int>("B", 2));
myList.Add(new KeyValuePair<string, int>("A", 1));
myList.Add(new KeyValuePair<string, int>("C", 3));
myList.Add(new KeyValuePair<string, int>("A", 5));
myList.Add(new KeyValuePair<string, int>("X", 9));
myList.Add(new KeyValuePair<string, int>("Z", 7));

I would like to find out index of this list by the key of keyvalue pair. So, index of A would be 0,2 and 4 and index of Z would be 6.

To find index which is present only once, I could do the following..

int o = myList.IndexOf((from val in myList where val.Key == "Z" select val).SingleOrDefault());

But how do I get index of val.Key == "A".

Someone suggested I look at the question Get indexes of all matching values from list using Linq and closed my question despite my question being about keyvaluepair list and the above question about string list ...

Based on that I tried unsuccessfully..

var result = Enumerable.Range(0, myList.Count)
             .Where(kvp => kvp.Key == "A")
             .ToList();

and

var result1 =   myList.Select((x, i) => new {x, i})
                  .Where(x => x.Key == "A")
                  .Select(x => x.i);

Received Errors:

Compilation error : 'int' does not contain a definition for 'Key' and no extension method 'Key' accepting a first argument of type 'int' could be found (are you missing a using directive or an assembly reference?) Compilation error: 'AnonymousType#1' does not contain a definition for 'Key' and no extension method 'Key' accepting a first argument of type 'AnonymousType#1' could be found (are you missing a using directive or an assembly reference?)

Would sincerely appreciate people answering questions or allowing others to answer and not closing them..

Upvotes: 1

Views: 1742

Answers (3)

Queue
Queue

Reputation: 1

Use string default = "A"; var result = myList.FindIndex( x => x.Key == default );

You will get the index from the list of key matching.

Upvotes: 0

Sweeper
Sweeper

Reputation: 271660

You didn't seem to really understand the code in the linked question, so I'll try to explain.

The approach with Enumerable.Range creates a sequence of numbers from 0 (the first index of myList) to myList.Count - 1 (the last index of myList), and then you use Where to filter these indices, based on a condition.

So really, the lambda parameter kvp here is an index, not a KeyValuePair. After the =>, you should write an expression that evaluates to true if the index should be included in the final list (i.e. the KVP at that index has the key you want), so let's do just that:

.Where(index => myList[index].Key == "A")

The second approach uses the overload of Select that takes a Func<TSource, int, TResult>, so in the Select lambda, you have access to both the KVP and the index. Here, we transform the two parameters into one single object (of an anonymous class). This is so that we can select just the index using the last Select, but filter based on the KVP in Where.

Your mistake is that you didn't realise that there is an anonymous class involved. In the Where lambda, you need to access .x to access the KVP part of the anonymous object, as opposed to the index I:

.Where(x => x.x.Key == "A") // the first x is the anonymous object, the second x is the KVP

Upvotes: 2

Tommy
Tommy

Reputation: 359

You can achieve this by doing the following:

public List<int> GetIndices(List<KeyValuePair<string, int>> myList, string query)
{
    List<int> indices = new List<int>();
    for (int i = 0; i < myList.Count; i++)
    {
        if (myList[i].Key == query) indices.Add(i);
    }

    return indices;
}

And below will work with any types:

public List<int> GetIndices<T, K>(List<KeyValuePair<T, K>> myList, T query)
{
    List<int> indices = new List<int>();
    int i = 0;
    myList.ForEach((pair) => { if (pair.Key.Equals(query)) indices.Add(i); i++; });
    return indices;
}

Upvotes: 1

Related Questions