2010-06-24 57 views
1

我有两个类别:LINQ内加入

List<int> ids; 
List<User> users; 

User具有ID,姓名等

我想内部连接这两个集合,并与来自第一ID返回一个新List<int>集合也在第二个集合中(用户标识)。

我是LINQ的新手,不知道从哪里开始。

谢谢。

回答

9

你并不需要用加入要做到这一点:

List<int> commonIds = ids.Intersect(users.Select(u => u.Id)).ToList(); 

编辑:针对在评论的问题,你可以得到用户的列表,而无需使用Join

var matchingUsers = users.Where(u => ids.Contains(u.Id)); 

但是这是非常低效的,因为Where子句必须扫描每个用户的id列表。我想加入将处理这种情况的最好办法:

List<User> matchingUsers = users.Join(ids, u => u.Id, id => id, (user, id) => user).ToList(); 
+0

你打我吧;) – 2010-06-24 23:02:21

+0

假设OP想要用户,而不是ID。它还可以在不加入连接的情况下完成吗? – spender 2010-06-24 23:07:18

+0

刚刚意识到我的id实际上是long和intersect函数,默认情况下只对int集合起作用(?)。 – 2010-06-25 01:07:26

2

在关系数据库术语,内部联接产生一个结果集,其中第一集合中的每个元素出现一次,每适配体在第二采集。如果第一个集合中的元素没有匹配的元素,它不会出现在结果集中。 Join方法由C#中的join子句调用,实现了内部联接。

本主题说明了如何进行内部的四个变体加入:

  • 简单内加入该关联基于一个简单的按键两个数据源 元素。

  • 一个内部联接,它基于 复合键将来自两个数据源的元素关联起来。组合键是一个由多个值组成的键,使您可以根据比一个属性更多的 关联元素。

  • 多次连接,其中连续的连接操作被相互追加到 之间。

  • 通过使用组连接实现的内部连接。

例 简单密钥加入实施例

下面的示例创建含有两个用户定义类型,Person和宠物的对象两个集合。查询使用C#中的join子句将Person对象与其所有者为Person的Pet对象进行匹配。 C#中的select子句定义了结果对象的外观。在这个例子中,结果对象是由所有者的名字和宠物名称组成的匿名类型。 C#

class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

class Pet 
{ 
    public string Name { get; set; } 
    public Person Owner { get; set; } 
} 

/// <summary> 
/// Simple inner join. 
/// </summary> 
public static void InnerJoinExample() 
{ 
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; 
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; 
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; 
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; 
    Person rui = new Person { FirstName = "Rui", LastName = "Raposo" }; 

    Pet barley = new Pet { Name = "Barley", Owner = terry }; 
    Pet boots = new Pet { Name = "Boots", Owner = terry }; 
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; 
    Pet bluemoon = new Pet { Name = "Blue Moon", Owner = rui }; 
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; 

    // Create two lists. 
    List<Person> people = new List<Person> { magnus, terry, charlotte, arlene, rui }; 
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy }; 

    // Create a collection of person-pet pairs. Each element in the collection 
    // is an anonymous type containing both the person's name and their pet's name. 
    var query = from person in people 
       join pet in pets on person equals pet.Owner 
       select new { OwnerName = person.FirstName, PetName = pet.Name }; 

    foreach (var ownerAndPet in query) 
    { 
     Console.WriteLine("\"{0}\" is owned by {1}", ownerAndPet.PetName, ownerAndPet.OwnerName); 
    } 
} 

// This code produces the following output: 
// 
// "Daisy" is owned by Magnus 
// "Barley" is owned by Terry 
// "Boots" is owned by Terry 
// "Whiskers" is owned by Charlotte 
// "Blue Moon" is owned by Rui 

注意,Person对象,其名字是“哈夫”没有出现在结果集中,因为那里是具有Pet.Owner等于人没有宠物的对象。 示例 复合键加入示例

除了基于一个属性关联元素外,还可以使用组合键来根据多个属性比较元素。为此,请为每个集合指定键选择器函数,以返回由要比较的属性组成的匿名类型。如果标注属性,则每个键的匿名类型中必须具有相同的标签。这些属性也必须以相同的顺序出现。

以下示例使用Employee对象列表和Student对象列表来确定哪些员工也是学生。这两种类型都有一个String类型的FirstName和LastName属性。从每个列表元素创建连接键的函数返回一个由每个元素的FirstName和LastName属性组成的匿名类型。连接操作比较这些组合键是否相等,并返回每个列表中名称和姓氏匹配的对象对。 C#

class Employee 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int EmployeeID { get; set; } 
} 

class Student 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int StudentID { get; set; } 
} 

/// <summary> 
/// Performs a join operation using a composite key. 
/// </summary> 
public static void CompositeKeyJoinExample() 
{ 
    // Create a list of employees. 
    List<Employee> employees = new List<Employee> { 
     new Employee { FirstName = "Terry", LastName = "Adams", EmployeeID = 522459 }, 
     new Employee { FirstName = "Charlotte", LastName = "Weiss", EmployeeID = 204467 }, 
     new Employee { FirstName = "Magnus", LastName = "Hedland", EmployeeID = 866200 }, 
     new Employee { FirstName = "Vernette", LastName = "Price", EmployeeID = 437139 } }; 

    // Create a list of students. 
    List<Student> students = new List<Student> { 
     new Student { FirstName = "Vernette", LastName = "Price", StudentID = 9562 }, 
     new Student { FirstName = "Terry", LastName = "Earls", StudentID = 9870 }, 
     new Student { FirstName = "Terry", LastName = "Adams", StudentID = 9913 } }; 

    // Join the two data sources based on a composite key consisting of first and last name, 
    // to determine which employees are also students. 
    IEnumerable<string> query = from employee in employees 
           join student in students 
           on new { employee.FirstName, employee.LastName } 
           equals new { student.FirstName, student.LastName } 
           select employee.FirstName + " " + employee.LastName; 

    Console.WriteLine("The following people are both employees and students:"); 
    foreach (string name in query) 
     Console.WriteLine(name); 
} 

// This code produces the following output: 
// 
// The following people are both employees and students: 
// Terry Adams 
// Vernette Price 

例 多重联实施例

任何数量的连接操作的可以被附加到彼此以执行多个连接。 C#中的每个连接子句都将指定的数据源与前一个连接的结果关联起来。

以下示例创建三个集合:一个Person对象列表,一个Cat对象列表以及一个Dog对象列表。

C#中的第一个连接子句根据与Cat.Owner匹配的Person对象匹配人员和猫。它返回一系列包含Person对象和Cat.Name的匿名类型。

C#中的第二个连接子句基于由Person类型的Owner属性组成的组合键,将第一个连接返回的匿名类型与提供的Dog列表中的Dog对象相关联,动物的名字。它返回包含每个匹配对的Cat.Name和Dog.Name属性的匿名类型序列。因为这是一个内部连接,所以只返回第一个数据源中第二个数据源中匹配的那些对象。 C#

class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

class Pet 
{ 
    public string Name { get; set; } 
    public Person Owner { get; set; } 
} 

class Cat : Pet 
{ } 

class Dog : Pet 
{ } 

public static void MultipleJoinExample() 
{ 
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; 
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; 
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; 
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; 
    Person rui = new Person { FirstName = "Rui", LastName = "Raposo" }; 
    Person phyllis = new Person { FirstName = "Phyllis", LastName = "Harris" }; 

    Cat barley = new Cat { Name = "Barley", Owner = terry }; 
    Cat boots = new Cat { Name = "Boots", Owner = terry }; 
    Cat whiskers = new Cat { Name = "Whiskers", Owner = charlotte }; 
    Cat bluemoon = new Cat { Name = "Blue Moon", Owner = rui }; 
    Cat daisy = new Cat { Name = "Daisy", Owner = magnus }; 

    Dog fourwheeldrive = new Dog { Name = "Four Wheel Drive", Owner = phyllis }; 
    Dog duke = new Dog { Name = "Duke", Owner = magnus }; 
    Dog denim = new Dog { Name = "Denim", Owner = terry }; 
    Dog wiley = new Dog { Name = "Wiley", Owner = charlotte }; 
    Dog snoopy = new Dog { Name = "Snoopy", Owner = rui }; 
    Dog snickers = new Dog { Name = "Snickers", Owner = arlene }; 

    // Create three lists. 
    List<Person> people = 
     new List<Person> { magnus, terry, charlotte, arlene, rui, phyllis }; 
    List<Cat> cats = 
     new List<Cat> { barley, boots, whiskers, bluemoon, daisy }; 
    List<Dog> dogs = 
     new List<Dog> { fourwheeldrive, duke, denim, wiley, snoopy, snickers }; 

    // The first join matches Person and Cat.Owner from the list of people and 
    // cats, based on a common Person. The second join matches dogs whose names start 
    // with the same letter as the cats that have the same owner. 
    var query = from person in people 
       join cat in cats on person equals cat.Owner 
       join dog in dogs on 
       new { Owner = person, Letter = cat.Name.Substring(0, 1) } 
       equals new { dog.Owner, Letter = dog.Name.Substring(0, 1) } 
       select new { CatName = cat.Name, DogName = dog.Name }; 

    foreach (var obj in query) 
    { 
     Console.WriteLine(
      "The cat \"{0}\" shares a house, and the first letter of their name, with \"{1}\".", 
      obj.CatName, obj.DogName); 
    } 
} 

// This code produces the following output: 
// 
// The cat "Daisy" shares a house, and the first letter of their name, with "Duke". 
// The cat "Whiskers" shares a house, and the first letter of their name, with "Wiley". 

例 内部联接,通过使用分组加入实施例

以下示例说明如何实现由使用一组连接的内连接。

在查询1中,Person对象列表根据匹配Pet.Owner属性的Person,被组加入到Pet对象列表中。组联接创建一个中间组的集合,其中每个组由一个Person对象和一系列匹配的Pet对象组成。

通过在查询中添加第二个从句,该序列序列被合并(或展平)为一个更长的序列。最终序列的元素类型由select子句指定。在此示例中,该类型是由每个匹配对的Person.FirstName和Pet.Name属性组成的匿名类型。

query1的结果等同于通过使用不带into子句的join子句执行内部连接而获得的结果集。 query2变量演示了这个等价的查询。 C#

class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

class Pet 
{ 
    public string Name { get; set; } 
    public Person Owner { get; set; } 
} 

/// <summary> 
/// Performs an inner join by using GroupJoin(). 
/// </summary> 
public static void InnerGroupJoinExample() 
{ 
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" }; 
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" }; 
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" }; 
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" }; 

    Pet barley = new Pet { Name = "Barley", Owner = terry }; 
    Pet boots = new Pet { Name = "Boots", Owner = terry }; 
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte }; 
    Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry }; 
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus }; 

    // Create two lists. 
    List<Person> people = new List<Person> { magnus, terry, charlotte, arlene }; 
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy }; 

    var query1 = from person in people 
       join pet in pets on person equals pet.Owner into gj 
       from subpet in gj 
       select new { OwnerName = person.FirstName, PetName = subpet.Name }; 

    Console.WriteLine("Inner join using GroupJoin():"); 
    foreach (var v in query1) 
    { 
     Console.WriteLine("{0} - {1}", v.OwnerName, v.PetName); 
    } 

    var query2 = from person in people 
       join pet in pets on person equals pet.Owner 
       select new { OwnerName = person.FirstName, PetName = pet.Name }; 

    Console.WriteLine("\nThe equivalent operation using Join():"); 
    foreach (var v in query2) 
     Console.WriteLine("{0} - {1}", v.OwnerName, v.PetName); 
} 

// This code produces the following output: 
// 
// Inner join using GroupJoin(): 
// Magnus - Daisy 
// Terry - Barley 
// Terry - Boots 
// Terry - Blue Moon 
// Charlotte - Whiskers 
// 
// The equivalent operation using Join(): 
// Magnus - Daisy 
// Terry - Barley 
// Terry - Boots 
// Terry - Blue Moon 
// Charlotte - Whiskers 

编译代码

  • Visual Studio创建一个新的控制台应用程序项目。

  • 添加对System.Core.dll的引用,如果它尚未引用。

  • 包含System.Linq命名空间。

  • 将示例中的代码复制并粘贴到Main方法下方的program.cs文件 中。将一行代码添加到Main方法中,以便调用 您粘贴的方法。

  • 运行该程序。

+0

尼斯努力在具有详细答案,尽管简洁在可能的情况下是首选。 – 2017-12-04 22:21:07