在LINQ中,SelectMany是一個非常有用的擴展方法。它可以將嵌套序列中的元素平鋪到單個序列中,也可以在集合中選擇多個元素,並將它們組合到單個序列中。在本文中,我們將從多個方面詳解SelectMany。
一、SelectMany方法的語法和用法
下面是SelectMany方法的語法:
public static IEnumerable<TResult> SelectMany<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, IEnumerable<TResult>> selector);
其中,source表示要枚舉的序列,selector表示要應用於每個元素的轉換函數。轉換函數接受集合的元素作為參數,並返回一個新的集合。
SelectMany方法的常見用法是將嵌套的集合轉換為單個序列。假設我們有以下類:
class Employee
{
public List<string> Skills { get; set; }
}
List<Employee> employees = new List<Employee>()
{
new Employee { Skills = new List<string> { "C#", "ASP.NET" } },
new Employee { Skills = new List<string> { "Java", "Spring" } },
new Employee { Skills = new List<string> { "Python", "Django" } }
};
現在,我們可以使用SelectMany方法將所有技能轉換為單個序列,如下所示:
var skills = employees.SelectMany(e => e.Skills);
上述代碼等效於以下代碼:
var skills = employees
.SelectMany(e => e.Skills, (e, skill) => new { Employee = e, Skill = skill })
.Select(a => a.Skill);
上述代碼首先將每個員工的技能列表與員工的對象組合起來,然後再選擇技能。
二、SelectMany方法和Join方法的比較
在使用LINQ進行查詢時,我們還可以使用Join方法將兩個集合組合成一個單獨的結果集。然而,SelectMany方法和Join方法之間有一些重要的區別。
Join方法需要兩個集合的公共鍵來進行匹配。然而,在SelectMany方法中,我們可以按任意方式轉換集合中的元素,而不需要關心它們之間是否有任何聯繫。
例如,假設我們有以下兩個類:
class Order
{
public int Id { get; set; }
public List<string> Products { get; set; }
}
class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
現在,我們可以使用Join方法將訂單和產品組合成單個結果集:
var orderDetails = orders.Join(products, o => o.Products, p => p.Name, (o, p) => new
{
OrderId = o.Id,
ProductName = p.Name,
ProductPrice = p.Price
});
但是,如果每個訂單中有多個相同的產品,那麼Join方法將返回多個結果行,這很難處理。如果您只想返回每個產品的單個結果行,則可以使用SelectMany方法來平鋪訂單的產品列表,如下所示:
var orderDetails = orders
.SelectMany(o => o.Products, (o, p) => new { Order = o.Id, Product = p })
.Join(products, op => op.Product, p => p.Name, (op, p) => new
{
OrderId = op.Order,
ProductName = p.Name,
ProductPrice = p.Price
});
上述代碼通過SelectMany方法將每個訂單的產品列表平鋪,並創建一個新的匿名類型,其中包含訂單和產品。然後,Join方法將產品與產品列表匹配,並返回單個結果行,其中包含訂單ID、產品名稱和產品價格。
三、SelectMany方法的笛卡爾積功能
除了將集合轉換為單個序列之外,SelectMany方法還可以使用其笛卡爾積功能,將多個序列組合成單個序列。
假設我們有以下兩個類:
class User
{
public int Id { get; set; }
public List<int> RoleIds { get; set; }
}
class Role
{
public int Id { get; set; }
public string Name { get; set; }
}
現在,我們可以使用SelectMany方法將用戶和角色組合成單個結果行,如下所示:
var userRoles = users.SelectMany(u => roles.Select(r => new
{
UserId = u.Id,
RoleId = r.Id,
RoleName = r.Name
}));
上述代碼使用SelectMany方法將每個用戶和每個角色組合成一個結果行,並為每個結果行設置相應的用戶ID、角色ID和角色名稱。
四、SelectMany方法的實現原理
最後,讓我們詳細了解SelectMany方法的實現原理。
當我們調用SelectMany方法時,它將遍歷源序列中的每個元素,並將轉換函數應用於每個元素。然後,對於每個轉換函數返回的集合,它將使用foreach循環遍歷它,並將其中的每個元素添加到單個結果序列中。
這意味著,如果轉換函數返回空集合,SelectMany方法不會添加任何元素到結果序列中。
因此,我們可以使用SelectMany方法來過濾集合中的元素。例如,假設我們有以下集合:
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
現在,我們可以使用SelectMany方法來過濾所有偶數,如下所示:
var oddNumbers = numbers.SelectMany(n => n % 2 == 0 ? Enumerable.Empty<int>() : new List<int> { n });
上述代碼使用SelectMany方法將所有奇數添加到結果序列中。如果集合中的元素是偶數,則轉換函數返回空集合,不會將其添加到結果序列中。
五、總結
在本文中,我們詳細介紹了SelectMany方法,包括其語法和用法、與Join方法的比較、笛卡爾積功能以及實現原理。掌握這些知識後,您將能夠更好地使用SelectMany方法進行序列的轉換和過濾,提高LINQ查詢的效率。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/153856.html