Novastorm
Novastorm

Reputation: 1458

Removing specific values from a Dictionary C# with Linq

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.

Upvotes: 2

Views: 3635

Answers (3)

Matthew Watson
Matthew Watson

Reputation: 109567

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

Upvotes: 3

gmn
gmn

Reputation: 4319

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

Upvotes: 0

Nico
Nico

Reputation: 3542

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

Upvotes: 1

Related Questions