Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A LINQ query with grouping and filtering of special groups

Tags:

c#

.net

linq

I have a class...

class Document
{
    public int GroupID  { get; set; }
    public bool Valid { get; set; }
    // more
}

... and a list of instances: IEnumerable<Document> documents. In a first step which runs object by object through this list those documents have been validated, which means: the property Valid will be true for some objects and false for other objects in the list.

Now in a second step I have to do the following:

  • If for at least one document per document group (defined by all documents with the same GroupID) the flag Valid is false then set Valid to false for all documents of the group.

To do this I have created so far the following code fragment:

var q = from d in documents
        group d by d.GroupID;
// q is now of type IEnumerable<IGrouping<int, Document>>

foreach (var dg in q) // dg = "document group", of type IGrouping<int, Document>
{
    if (dg.Any(d => !d.Valid))
    {
        foreach (var d in dg)
            d.Valid = false;
    }
}

I believe, this does what I want (I didn't test it until now, though) but not very efficiently.

Question: Is there a way to improve this code, especially to move the semantics of the Any method in the outer foreach loop "somehow" into the initial LINQ query, so that q only represents the groups which have at least one invalid document? (Also I am obviously not interested in groups which have only one element, so those groups could be filtered out as well.)

Thank you for suggestions in advance!

like image 666
Slauma Avatar asked Nov 09 '10 15:11

Slauma


Video Answer


1 Answers

I think this does what you want:

var q = from d in documents
        group d by d.GroupID into g
        where g.Count() > 1 && g.Any(d => !d.Valid)
        select g;

foreach (var dg in q)
{
    foreach (var d in dg)
    {
        d.Valid = false;
    }
}

The top part in fluent syntax would look like:

var q = documents.GroupBy(d => d.GroupID)
            .Where(g => g.Count() > 1 && g.Any(d => !d.Valid));
like image 167
kevev22 Avatar answered Sep 22 '22 02:09

kevev22