2

I have a dictionary which holds information from a parsed test run. The key is the name of the method and the value is a list of TestRunProperties. My dictionary contains all methods from a test run and I would like to remove the methods which failed during a test run. Is this possible to do with Linq?

TestRunProperties class:

public class TestRunProperties
{
    public string computerName { get; set; }
    public TimeSpan duration { get; set; }
    public string startTime { get; set; }
    public string endTime { get; set; }
    public string testName { get; set; }
    public string outcome { get; set; }
}

Dictionary:

//Key is the name of the method, value is the properties associated with each run
private static Dictionary<string, List<TestRunProperties>> runResults = new Dictionary<string, List<TestRunProperties>>();

I've tried this but I think I'm getting confused with the Where part:

runResults.Remove(runResults.Where(methodName => methodName.Value.Where(method => method.outcome.ToLower().Equals("failed"))));

I'm quite new to Linq and Lambda and I'm still trying to understand how to access data like this.

1
  • Thank you all for your help, all really great answers! Commented Oct 7, 2016 at 10:54

3 Answers 3

3

Just use a loop to remove the items you don't want. You can write an extension method to make it easier to call:

public static class DictionaryExt
{
    public static void RemoveAll<K, V>(this IDictionary<K, V> dict, Func<K, V, bool> predicate)
    {
        foreach (var key in dict.Keys.ToArray().Where(key => predicate(key, dict[key])))
            dict.Remove(key);
    }
}

This usually will be more efficient than creating an entirely new dictionary, especially if the number of items being removed is relatively low compared to the size of the dictionary.

Your calling code would look like this:

runResults.RemoveAll((key, methodName) => methodName.Value.Where(method => method.outcome.ToLower().Equals("failed")));

(I chose the name RemoveAll() to match List.RemoveAll().)

Sign up to request clarification or add additional context in comments.

Comments

1

You could create a new dictionary by filtering out the invalid ones:

var filtered = runResults.ToDictionary(p => p.Key, p => p.Value.Where(m => m.outcome.ToLower() != "failed").ToList());

Ok, grrrrrr was faster :-)

1 Comment

Thank you this has worked! grrrrrr answer was close but missed out a point or two :)
0

To be honest you're probably better off selecting a new dictionary from the existing one:

runResults.Select().ToDictionary(x => x.Key, x => x.Value.Where(x => x.Value.outcome != "failed"));

*editted to reflect list in the dictionary.

Actually, you can get rid of the ones with no successful results by doing this too:

runResults.Select(x => new { x.Key, x.Value.Where(x => x.Value.outcome != "failed")} ).Where(x => x.Value.Any()).ToDictionary(x => x.Key, x => x.Value);

2 Comments

I think there's a part missing with the above; Value is a list rather than an individual TestRunProperty so I can't access the .outcome from it
Ah so you just need to query down one more level

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.