Difference Between Select and SelectMany

后端 未结 17 1110
长情又很酷
长情又很酷 2020-11-22 05:21

I\'ve been searching the difference between Select and SelectMany but I haven\'t been able to find a suitable answer. I need to learn the differenc

相关标签:
17条回答
  • 2020-11-22 05:33

    Just for an alternate view that may help some functional programmers out there:

    • Select is map
    • SelectMany is bind (or flatMap for your Scala/Kotlin people)
    0 讨论(0)
  • 2020-11-22 05:35

    One more example how SelectMany + Select can be used in order to accumulate sub array objects data.

    Suppose we have users with they phones:

    class Phone { 
        public string BasePart = "555-xxx-xxx"; 
    }
    
    class User { 
        public string Name = "Xxxxx";
        public List<Phone> Phones; 
    }
    

    Now we need to select all phones' BaseParts of all users:

    var usersArray = new List<User>(); // array of arrays
    List<string> allBaseParts = usersArray.SelectMany(ua => ua.Phones).Select(p => p.BasePart).ToList();
    
    0 讨论(0)
  • 2020-11-22 05:36

    Some SelectMany may not be necessary. Below 2 queries give the same result.

    Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)
    
    Orders.Where(o=>o.Customer.Name=="Tom")
    

    For 1-to-Many relationship,

    1. if Start from "1", SelectMany is needed, it flattens the many.
    2. if Start from "Many", SelectMany is not needed. (still be able to filter from "1", also this is simpler than below standard join query)

    from o in Orders
    join c in Customers on o.CustomerID equals c.ID
    where c.Name == "Tom"
    select o
    
    0 讨论(0)
  • 2020-11-22 05:36

    Here is a code example with an initialized small collection for testing:

    class Program
    {
        static void Main(string[] args)
        {
            List<Order> orders = new List<Order>
            {
                new Order
                {
                    OrderID = "orderID1",
                    OrderLines = new List<OrderLine>
                    {
                        new OrderLine
                        {
                            ProductSKU = "SKU1",
                            Quantity = 1
                        },
                        new OrderLine
                        {
                            ProductSKU = "SKU2",
                            Quantity = 2
                        },
                        new OrderLine
                        {
                            ProductSKU = "SKU3",
                            Quantity = 3
                        }
                    }
                },
                new Order
                {
                    OrderID = "orderID2",
                    OrderLines = new List<OrderLine>
                    {
                        new OrderLine
                        {
                            ProductSKU = "SKU4",
                            Quantity = 4
                        },
                        new OrderLine
                        {
                            ProductSKU = "SKU5",
                            Quantity = 5
                        }
                    }
                }
            };
    
            //required result is the list of all SKUs in orders
            List<string> allSKUs = new List<string>();
    
            //With Select case 2 foreach loops are required
            var flattenedOrdersLinesSelectCase = orders.Select(o => o.OrderLines);
            foreach (var flattenedOrderLine in flattenedOrdersLinesSelectCase)
            {
                foreach (OrderLine orderLine in flattenedOrderLine)
                {
                    allSKUs.Add(orderLine.ProductSKU);
                }
            }
    
            //With SelectMany case only one foreach loop is required
            allSKUs = new List<string>();
            var flattenedOrdersLinesSelectManyCase = orders.SelectMany(o => o.OrderLines);
            foreach (var flattenedOrderLine in flattenedOrdersLinesSelectManyCase)
            {
                allSKUs.Add(flattenedOrderLine.ProductSKU);
            }
    
           //If the required result is flattened list which has OrderID, ProductSKU and Quantity,
           //SelectMany with selector is very helpful to get the required result
           //and allows avoiding own For loops what according to my experience do code faster when
           // hundreds of thousands of data rows must be operated
            List<OrderLineForReport> ordersLinesForReport = (List<OrderLineForReport>)orders.SelectMany(o => o.OrderLines,
                (o, ol) => new OrderLineForReport
                {
                    OrderID = o.OrderID,
                    ProductSKU = ol.ProductSKU,
                    Quantity = ol.Quantity
                }).ToList();
        }
    }
    class Order
    {
        public string OrderID { get; set; }
        public List<OrderLine> OrderLines { get; set; }
    }
    class OrderLine
    {
        public string ProductSKU { get; set; }
        public int Quantity { get; set; }
    }
    class OrderLineForReport
    {
        public string OrderID { get; set; }
        public string ProductSKU { get; set; }
        public int Quantity { get; set; }
    }
    
    0 讨论(0)
  • 2020-11-22 05:39

    Consider this example :

            var array = new string[2]
            {
                "I like what I like",
                "I like what you like"
            };
            //query1 returns two elements sth like this:
            //fisrt element would be array[5]  :[0] = "I" "like" "what" "I" "like"
            //second element would be array[5] :[1] = "I" "like" "what" "you" "like"
            IEnumerable<string[]> query1 = array.Select(s => s.Split(' ')).Distinct();
    
            //query2 return back flat result sth like this :
            // "I" "like" "what" "you"
            IEnumerable<string> query2 = array.SelectMany(s => s.Split(' ')).Distinct();
    

    So as you see duplicate values like "I" or "like" have been removed from query2 because "SelectMany" flattens and projects across multiple sequences. But query1 returns sequence of string arrays. and since there are two different arrays in query1 (first and second element), nothing would be removed.

    0 讨论(0)
  • 2020-11-22 05:39

    It is the best way to understand i think.

                var query =
                Enumerable
                    .Range(1, 10)
                    .SelectMany(ints => Enumerable.Range(1, 10), (a, b) => $"{a} * {b} = {a * b}")
                    .ToArray();
    
            Console.WriteLine(string.Join(Environment.NewLine, query));
    
            Console.Read();
    

    Multiplication Table example.

    0 讨论(0)
提交回复
热议问题