简体   繁体   中英

Linq Expression to Query Two List

I have two types of objects. Object A contains a field of id and Object B contains a field of id and a field of datetime. Now I have a list of object A and a list of object B. I want to get a list of object B where the id of object B is equal to the id of object A at the same time that this object B is the first object in the object B list ordered descending by the date field corresponding to one id for both objects. How can I write one single linq query expression to get this list instead of using a loop to loop through to search the target object B? Thanks in advance.

Without your code it's hard to tell if this will work but seems like you want something like this

var matchingB = listObjectB.OrderByDescending(b => b.DateTime)
           .Where(b => listObjectA.Any(a => a.Id == b.Id))
           .GroupBy(b => b.Id).ToList();

I strongly suggest using joins for comparing two lists by an ID-like field - that's what joins are for and this is generally the most efficient way.

If you can assume, that the first list has only unique IDs (as you can often assume about IDs), this will do the job:

var selected1 = listA
    .Join(
        listB
            .GroupBy(b => b.Id)
            .Select(g => g.OrderBy(b => b.Date).First()),
        a => a.Id, 
        b => b.Id, 
        (a, b) => b);

The following query would yield better performance, if IDs in listA drastically limit the number of IDs in listB (as the grouping and ordering are applied to this limited list).

var selected2 = listA
    .Join(listB, a => a.Id, b => b.Id, (a, b) => b)
    .GroupBy(b => b.Id)
    .Select(g => g.OrderBy(b => b.Date).First());

The second methods works, when there are repeated IDs in listA. If I had reasons to believe that there may be many many repeated IDs in listA, I would aply Distinct (which would also fix selected1 in case of repeated IDs). For example, without EqualityComparer:

var selected3 = listA
    .Select(a=>a.Id)
    .Distinct()
    .Join(listB, id => id, b => b.Id, (id, b) => b)
    .GroupBy(b => b.Id)
    .Select(g => g.OrderBy(b => b.Date).First());

In LINQ, you can have multiple from 's if you want to query more than one data source, so for your problem I would do something like this:

internal class Program
{
    private static void Main(string[] args)
    {
        //The below code is just me pulling some data out of the air to work with
        var listOfIds = new List<ObjectA>();
        var data = new List<ObjectB>();

        for (var i = 0; i < 5; i++)
        {
            if (i % 2 == 0)
            {
                listOfIds.Add(new ObjectA(i));
            }

            data.Add(new ObjectB(i, DateTime.Now.AddDays(i)));
        }

        //Now we have two ILists which match the type of data you were talking about, and you simply query them like so
        var datesWhereIdIsInList = (from id in listOfIds
                                    from date in data
                                    where id.Id == date.Id
                                    select date).OrderByDescending(x => x.DateTime).ToList();
    }

    private class ObjectA
    {
        private readonly int _id;

        public ObjectA(int id)
        {
            _id = id;
        }

        public int Id
        {
            get { return _id; }
        }
    }

    private class ObjectB
    {
        private readonly int _id;
        private readonly DateTime _dateTime;

        public ObjectB(int id, DateTime dateTime)
        {
            _id = id;
            _dateTime = dateTime;
        }

        public int Id
        {
            get { return _id; }
        }

        public DateTime DateTime
        {
            get { return _dateTime; }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM