0

I have 2 lists containing 2 different types of object. Is it possible to compare the objects from both lists and create a new list which contains objects with matching property values?

For example if I had a list of buses (with a property 'busID') and a list of drivers (also with a property 'busID'). Could I create a new list where (buses.busesID = drivers.busID)?

I realise this question is vague and contains no example code. I'm pretty stuck here though.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
user1769279
  • 33
  • 1
  • 7

3 Answers3

1

You can use LINQ to join these two collections on this ID, producing for example a tuple of bus and its driver. Using LINQ syntax, it would look like this:

var result = from bus in buses
             join driver in drivers on bus.busID equals driver.busID
             select new { Bus = bus, Driver = driver }

This may introduce several new features for you, like the LINQ itself, or anonymous type definition.

The result is a query, which is executed lazily and produces a collection of bus+driver couples.

Honza Brestan
  • 10,637
  • 2
  • 32
  • 43
  • I'm looking to 'assign' a driver to a bus. I thought this would be a simple solution to list all the drivers which will be using a certain bus. Would this method work fine or do you know of a more elegant solution? – user1769279 Nov 27 '12 at 09:06
  • Take a look at other LINQ methods, they provide many ways to look at collections - you can filter them, project items, aggregate items... If you want to list drivers of a specified bus, it's an easy filter (`Where` method/clause). **[101 LINQ Samples](http://code.msdn.microsoft.com/101-LINQ-Samples-3fb9811b)** helped me a lot in the beginning. – Honza Brestan Nov 27 '12 at 09:14
  • Thanks a lot for the help man! How can I add the resulting tuples from this query to a list which can be displayed in a WinForms listbox? – user1769279 Nov 27 '12 at 11:20
  • You can either call `ToList()`, `ToArray()` or similar method on the `result` to get a good old collection object, or enumerate it with `foreach` loop and fill the listbox in the loop body. – Honza Brestan Nov 27 '12 at 11:27
0

Try this:

var query =
    from driver in drivers
    join bus in buses on driver.busID equals bus.busID
    select new { driver, bus };

var results = query.ToList();
Enigmativity
  • 113,464
  • 11
  • 89
  • 172
0

If you are after a more abstract solution, then you can use reflection.

    class A
    {
        public int x { get; set; }
        public int y { get; set; }
    }

    class B
    {
        public int y { get; set; }
        public int z { get; set; }
    }

    static List<A> listA = new List<A>();
    static List<B> listB = new List<B>();

    static void Main(string[] args)
    {
        listA.Add(new A {x = 0, y = 1});
        listA.Add(new A {x = 0, y = 2});
        listB.Add(new B {y = 2, z = 9});
        listB.Add(new B {y = 3, z = 9});

        // get all properties from classes A & B and find ones with matching names and types
        var propsA = typeof(A).GetProperties();
        var propsB = typeof(B).GetProperties();
        var matchingProps = new List<Tuple<PropertyInfo, PropertyInfo>>();
        foreach (var pa in propsA)
        {
            foreach (var pb in propsB)
            {
                if (pa.Name == pb.Name && pa.GetType() == pb.GetType())
                {
                    matchingProps.Add(new Tuple<PropertyInfo, PropertyInfo>(pa, pb));
                }
            }
        }

        // foreach matching property, get the value from each element in list A and try to find matching one from list B
        var matchingAB = new List<Tuple<A, B>>();
        foreach (var mp in matchingProps)
        {
            foreach (var a in listA)
            {
                var valA = mp.Item1.GetValue(a, null);

                foreach (var b in listB)
                {
                    var valB = mp.Item2.GetValue(b, null);

                    if (valA.Equals(valB))
                    {
                        matchingAB.Add(new Tuple<A, B>(a, b));
                    }
                }
            }
        }

        Console.WriteLine(matchingAB.Count); // this prints 1 in this case
    }

Sidenote: Tuple is a .NET 4 class, if you cannot use that, then you can easily write your own: Equivalent of Tuple (.NET 4) for .NET Framework 3.5

Community
  • 1
  • 1
Mike Trusov
  • 1,958
  • 1
  • 15
  • 23