Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to: Select Distinct objects<T> from multiple Lists<T> with 1 or more properties of same type

Tags:

c#

linq

So this is a design question that has vexed me for hours, and I have to reach out to the group for an assist. I have a collection with thousands of shared entities, and need to retrieve a distinct list of managers from three different properties contained in two lists, two managers in the Stores list, and one manager from warehouse collection.

To simplify the problem, I've written a simple console program that highlights the challenge. I tossed it together, so yes, I know it's inefficient, but it demonstrates the problem:

    public class Program
    {
        static void Main(string[] args)
        {
            DistributionGroup d = new DistributionGroup();
            Console.WriteLine("====Store Managers====");
            foreach(Manager m in d.Stores.Select(m => m.StoreManager).Distinct())
            {
                Console.WriteLine("{0}:{1}", m.Id, m.Name);
            }

            Console.WriteLine("=====Inv. Managers=====");
            foreach (Manager m in d.Stores.Select(m => m.InventoryManager).Distinct())
            {
                Console.WriteLine("{0}:{1}", m.Id, m.Name);
            }

            Console.WriteLine("===Warehouse Managers===");
            foreach (Manager m in d.Warehouses.Select(m => m.WarehouseManager).Distinct())
            {
                Console.WriteLine("{0}:{1}", m.Id, m.Name);
            }                
        }
    }
    public class DistributionGroup
    {
        private Manager m1 = new Manager(1, "Bob Wilson");
        private Manager m2 = new Manager(2, "Chris Warren");
        private Manager m3 = new Manager(3, "Mike Olsen");
        private Manager m4 = new Manager(4, "Aaron Erikson");

        public List<RetailStore> Stores;
        public List<Warehouse> Warehouses;

        public DistributionGroup()
        {
            RetailStore s1 = new RetailStore(1, m1, m1);
            RetailStore s2 = new RetailStore(2, m1, m3);
            RetailStore s3 = new RetailStore(3, m2, m2);
            Warehouse w1 = new Warehouse(1, m4);
            Warehouse w2 = new Warehouse(2, m2);

            Stores = new List<RetailStore>();
            Stores.Add(s1);
            Stores.Add(s2);
            Stores.Add(s3);

            Warehouses = new List<Warehouse>();
            Warehouses.Add(w1);
            Warehouses.Add(w2);
        }
    }

    public class Manager
    {
        public int Id;
        public string Name;
        public Manager(int id, string name)
        {
            Id = id; Name = name;
        }
    }
    public class RetailStore
    {
        public int Id;
        public Manager StoreManager;
        public Manager InventoryManager;
        public RetailStore(int id, Manager mgr, Manager inventoryMgr)
        {
            Id = id;
            StoreManager = mgr;
            InventoryManager = inventoryMgr;
        }
    }

    public class Warehouse
    {
        public int Id;
        public Manager WarehouseManager;
        public Warehouse(int id, Manager mgr)
        {
            Id = id;
            WarehouseManager = mgr;
        }
    }

What I need to do is generate a distinct list of Managers from all three properties:

  1. RetailStore.StoreManager
  2. RetailStore.InventoryManager
  3. Warehouse.WarehouseManager

So following the example, the console output would simply be:

1:Bob Wilson
2:Chris Warren
3:Mike Olsen
4:Aaron Erikson

I've been trying to figure out the syntax, but LINQ is not a strength, and I'm hoping the group can help me out.

like image 490
jaeckyl Avatar asked Jan 28 '26 06:01

jaeckyl


1 Answers

Seems like you need to use Enumerable.Union

var allManagers = d.Stores.Select(m => m.StoreManager).Union(d.Stores.Select(m => m.InventoryManager))
                                                      .Union(d.Warehouses.Select(m => m.WarehouseManager));
foreach (Manager m in allManagers)
{
    Console.WriteLine("{0}:{1}", m.Id, m.Name);
}   

Note that Union returns unique values from input sequences so no need to call Distinct.

like image 196
tukaef Avatar answered Jan 29 '26 20:01

tukaef