alecam
alecam

Reputation: 197

C# Linq on a list of dictionaries to filter it

I'm having a problem not knowing how to use LINQ properly.

I have a List of Dictionaries(string, object) like this:

[0] -> "field1":1500, "field2":"dog", "field3":"blue"
[1] -> "field1":1700, "field2":"cat", "field3":"brown"
[2] -> "field1":1500, "field2":"horse", "field3":"white"
[3] -> "field1":1900, "field2":"cow", "field3":"black"

I need to get from this a List of Dictionaries with only the Dictionaries that have the "field1" set to 1500, so the output should be:

[0] -> "field1":1500, "field2":"dog", "field3":"blue"
[1] -> "field1":1500, "field2":"horse", "field3":"white"

I tried doing it like this but I'm sure I'm nowhere near the right answer.

List<Dictionary<string, object>> output = input.SelectMany(r => r).Where(r => (r.Key == "field1") && (r.Value == 1500)).ToList();

Please can you suggest me a solution for this?

Thank you very much.

Upvotes: 2

Views: 4110

Answers (2)

MakePeaceGreatAgain
MakePeaceGreatAgain

Reputation: 37000

Whilst you could write your entire model as a collection of collections (of collections...) it´s merely a good idea as it´s impossible to understand and to maintain. You should definitly create your own classes, e.g.:

class MyClass
{
    public int Field1 { get; set; }
    public string Field2 { get; set; }
    public string Field3 { get; set; }
}

Now you can create instances of those types and don´t have to mess up with object. E.g.

var m = new MyType { Field1 = 1500, Field2 = "dog", Field3 = "blue" };

You can also put this into a collection:

var myList = new[] { m };

and even select elements from that list that satisfy your condition:

var result = myList.Where(x => x.Field1 == 1500);

Notice that Field1 is of type integer, so you get a compiler-error if you´re comparing the value with "MyValue" for example. In your solution the dicitonaries values are of type object, so you could store anything into Field1, not just numbers.

Apart from all this you should also use some meaningful names for your members, e.g. Color instead of Field2 and Animal instead of Field2.

Upvotes: 3

Matthew Watson
Matthew Watson

Reputation: 109567

This should work:

var result = 
    dicts.Where(
        d => d.TryGetValue("field1", out object value) && value is int i && i == 1500
    ).ToList();

This picks out all the dictionaries in the list that have a field called field1 (via the d.TryGetValue()) and where that value is also 1500.

Note that because the dictionary contains object and not int, you need to check if the value is int using is int i.

Also note that this syntax uses the C# version 7 or later.

Upvotes: 3

Related Questions