LINQ内连接

Mak*_*Vi. 4 .net c# linq

我有两个集合:

List<int> ids;
List<User> users;
Run Code Online (Sandbox Code Playgroud)

哪里User有id,名字等

我想内部加入这两个集合,并List<int>从第一个集合中返回一个新的id,它们也在第二个集合中(用户ID).

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

谢谢.

Lee*_*Lee 12

您不需要使用join来执行此操作:

List<int> commonIds = ids.Intersect(users.Select(u => u.Id)).ToList();
Run Code Online (Sandbox Code Playgroud)

编辑:在回复评论中的问题时,您可以获得用户列表而不使用Join:

var matchingUsers = users.Where(u => ids.Contains(u.Id));
Run Code Online (Sandbox Code Playgroud)

然而,这是非常低效的,因为该Where子句必须扫描每个用户的id列表.我认为加入将是处理这种情况的最佳方式:

List<User> matchingUsers = users.Join(ids, u => u.Id, id => id, (user, id) => user).ToList();
Run Code Online (Sandbox Code Playgroud)


Ali*_*mal 5

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

本主题介绍如何执行内部联接的四种变体:

  • 一个简单的内部联接,它基于一个简单的密钥关联来自两个数据源的元素.

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

  • 多个连接,其中连续的连接操作相互附加.

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

示例简单键连接示例

以下示例创建两个集合,其中包含两个用户定义类型Person和Pet的对象.该查询使用C#中的join子句将Person对象与其Owner为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
Run Code Online (Sandbox Code Playgroud)

请注意,LastName为"Huff"的Person对象不会出现在结果集中,因为没有Pet对象的Pet.Owner等于该Person.示例复合键连接示例

您可以使用复合键基于多个属性比较元素,而不是仅基于一个属性关联元素.为此,请为每个集合指定键选择器函数,以返回包含要比较的属性的匿名类型.如果标记属性,则每个键的匿名类型必须具有相同的标签.属性也必须以相同的顺序出现.

以下示例使用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
Run Code Online (Sandbox Code Playgroud)

示例多个连接示例

可以将任意数量的连接操作彼此附加以执行多连接.C#中的每个连接子句将指定的数据源与先前连接的结果相关联.

以下示例创建三个集合:Person对象列表,Cat对象列表和Dog对象列表.

C#中的第一个join子句根据与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".
Run Code Online (Sandbox Code Playgroud)

使用分组连接示例进行内连接示例

以下示例说明如何使用组连接实现内部联接.

在query1中,Person对象列表基于与Pet.Owner属性匹配的Person被分组连接到Pet对象列表.组连接创建一组中间组,其中每个组由一个Person对象和一系列匹配的Pet对象组成.

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

query1的结果等效于使用join子句而不使用into子句来执行内连接所获得的结果集.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
Run Code Online (Sandbox Code Playgroud)

编写代码

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

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

  • 包括System.Linq命名空间.

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

  • 运行程序.

  • 当您直接从在线资源复制时,您需要提供归属 https://learn.microsoft.com/en-us/dotnet/csharp/linq/perform-inner-joins (2认同)