Single LINQ query over 3 separate collections

I have an object that has 3 separate dictionaries. The value parameter for each dictionary implements the same interface. What is the best way to combine 3 dictionaries into one and execute one query so that the query results are a single IEnumerable?

Here's a rough idea of ​​what I'm trying to accomplish. My object DataSet

contains 3 dictionaries, each of which should be very small (in theory, some could contain up to 100 elements, but except in extreme cases they will always be less than 20 and usually 6 or less).

The purpose of the method GetAllId()

is to get the Id for multiple private fields in each element of each dictionary and return it as a single IEnumerable. Dictionary value objects all implement IIdQueryable, which defines a single method that will retrieve everything required Id

in the object.

I have two different ideas on how to accomplish what I want, but I'm not sure if there is a better way to do this?

public class DataSet
{
    Dictionary<Int32, Foo> dict1;
    Dictionary<CustomKey, Bar> dict2;
    Dictionary<Int32, Boo> dict3;

    public IEnumerable<Int32> GetAllId
    {
        // need to retrieve Id from dict1, dict2, and dict3.
        //  implementation ideas below
    }
}

      

Option 1

public IEnumerable<Int32> GetAllId
{
    var q1 = dict.Values.SelectMany(g => g.GetId());
    var q2 = dict.Values.SelectMany(g => g.GetId());
    var q3 = dict.Values.SelectMany(g => g.GetId());

    return q1.Concat(q2).Concat(q3);
}

      

Option 2

public IEnumerable<Int32> GetAllId
{
    var c1 = dict1.Values.Cast<IIdQueryable>();
    var c2 = dict2.Values.Cast<IIdQueryable>();
    var c3 = dict2.Values.Cast<IIdQueryable>();

    var collection = c1.Concat(c2).Concat(c3);

    return collection.SelectMany(g => g.GetId());
}

      

Method # 3

Since every object implements the same interface, is it possible to execute one LINQ query on all three objects without casting?

I personally like Method # 1 better as it does not include casting, but I think Method # 2 looks more readable.

If needed, here is a rough idea of ​​how the interface is implemented

public interface IIdQueryable
{
    IEnumerable<Int32> GetId();
}

public class Foo : IIdQueryable
{
    public IEnumerable<Int32> GetId()
    {
       //returns Id of all elements in this object
    }
}

public class Bar : IGuidQueryable
{
    public IEnumerable<Int32> GetId()
    {
       //returns Id of all elements in this object
    }
}

public class Boo : IGuidQueryable
{
    public IEnumerable<Int32> GetId()
    {
       //returns Id of all elements in this object
    }
}

      

EDIT:

The question title is the source of what I was hoping to do (i.e. do all 3 searches in one query without casting). I have explained this above.

+3


source to share


1 answer


You only need one call SelectMany

in the first approach:

public IEnumerable<Int32> GetAllId()
{
    return dict1.Values
                .Select(x => x.GetId())
                .Concat(dict2.Values.Select( x=> x.GetId()))
                .Concat(dict3.Values.Select(x => x.GetId()))
                .SelectMany(x => x);
}

      

Personally, I wouldn't glue this together, although the performance impact had no effect on keeping separate queries and just returning the concatenation like you did in the first example - this is more readable to me:



public IEnumerable<Int32> GetAllId()
{
    var q1 = dict1.Values.Select(g => g.GetId());
    var q2 = dict2.Values.Select(g => g.GetId());
    var q3 = dict3.Values.Select(g => g.GetId());

    return q1.Concat(q2)
             .Concat(q3)
             .SelectMany(x => x);
}

      

Now it looks pretty close to the second set already, but no throw is required.

+2


source







All Articles