设置操作 (C#)

LINQ 中的集运算是指根据相同或不同集合(或集)中是否存在等效元素来生成结果集的查询运算。

下节列出了执行集运算的标准查询运算符方法。

方法

方法名称 说明 C# 查询表达式语法 详细信息
Distinct 或 DistinctBy 删除集合中的重复值。 不适用。 Enumerable.Distinct
Enumerable.DistinctBy
Queryable.Distinct
Queryable.DistinctBy
Except 或 ExceptBy 返回差集,差集指位于一个集合但不位于另一个集合的元素。 不适用。 Enumerable.Except
Enumerable.ExceptBy
Queryable.Except
Queryable.ExceptBy
Intersect 或 IntersectBy 返回交集,交集指同时出现在两个集合中的元素。 不适用。 Enumerable.Intersect
Enumerable.IntersectBy
Queryable.Intersect
Queryable.IntersectBy
Union 或 UnionBy 返回并集,并集指位于两个集合中任一集合的唯一的元素。 不适用。 Enumerable.Union
Enumerable.UnionBy
Queryable.Union
Queryable.UnionBy

示例

以下一些示例依赖于表示太阳系中行星的 record 类型。

namespace SolarSystem;

record Planet(
    string Name,
    PlanetType Type,
    int OrderFromSun)
{
    public static readonly Planet Mercury =
        new(nameof(Mercury), PlanetType.Rock, 1);

    public static readonly Planet Venus =
        new(nameof(Venus), PlanetType.Rock, 2);

    public static readonly Planet Earth =
        new(nameof(Earth), PlanetType.Rock, 3);

    public static readonly Planet Mars =
        new(nameof(Mars), PlanetType.Rock, 4);

    public static readonly Planet Jupiter =
        new(nameof(Jupiter), PlanetType.Gas, 5);

    public static readonly Planet Saturn =
        new(nameof(Saturn), PlanetType.Gas, 6);

    public static readonly Planet Uranus =
        new(nameof(Uranus), PlanetType.Liquid, 7);

    public static readonly Planet Neptune =
        new(nameof(Neptune), PlanetType.Liquid, 8);

    // Yes, I know... not technically a planet anymore
    public static readonly Planet Pluto =
        new(nameof(Pluto), PlanetType.Ice, 9);
}

record Planet 是位置记录,需要 NameTypeOrderFromSun 参数来实例化它。 Planet 类型有多个 static readonly 行星实例。 这些是对著名行星的基于便利的定义。 成员 Type 标识地球类型。

namespace SolarSystem;

enum PlanetType
{
    Rock,
    Ice,
    Gas,
    Liquid
};

DistinctDistinctBy

以下示例演示字符串序列上 Enumerable.Distinct 方法的行为。 返回的序列包含输入序列的唯一元素。

显示 Distinct() 的行为的图。

string[] planets = { "Mercury", "Venus", "Venus", "Earth", "Mars", "Earth" };

IEnumerable<string> query = from planet in planets.Distinct()
                            select planet;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * Mercury
 * Venus
 * Earth
 * Mars
 */

DistinctByDistinct 的替代方法,它采用 keySelectorkeySelector 用作源类型的比较鉴别器。 请考虑以下行星阵列:

Planet[] planets =
{
    Planet.Mercury,
    Planet.Venus,
    Planet.Earth,
    Planet.Mars,
    Planet.Jupiter,
    Planet.Saturn,
    Planet.Uranus,
    Planet.Neptune,
    Planet.Pluto
};

在下面的代码中,行星根据其 PlanetType 进行区分,并显示每种类型的第一个行星:

foreach (Planet planet in planets.DistinctBy(p => p.Type))
{
    Console.WriteLine(planet);
}

// This code produces the following output:
//     Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 }
//     Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 }
//     Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 }
//     Planet { Name = Pluto, Type = Ice, OrderFromSun = 9 }

在前述 C# 代码中:

  • Planet 阵列按每个唯一行星类型的第一个匹配项进行不同的筛选。
  • 将生成的 planet 实例写入控制台。

ExceptExceptBy

以下示例演示 Enumerable.Except 的行为。 返回的序列只包含位于第一个输入序列但不位于第二个输入序列的元素。

此图显示 Except() 的操作

string[] planets1 = { "Mercury", "Venus", "Earth", "Jupiter" };
string[] planets2 = { "Mercury", "Earth", "Mars", "Jupiter" };

IEnumerable<string> query = from planet in planets1.Except(planets2)
                            select planet;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * Venus
 */

ExceptBy 方法是 Except 的替代方法,它采用可能是异构类型的两个序列和一个 keySelectorkeySelector 与第二个集合的类型相同,用作源类型的比较鉴别器。 请考虑以下行星阵列:

Planet[] planets =
{
    Planet.Mercury,
    Planet.Venus,
    Planet.Earth,
    Planet.Jupiter
};

Planet[] morePlanets =
{
    Planet.Mercury,
    Planet.Earth,
    Planet.Mars,
    Planet.Jupiter
};

若要在第一个集合中查找不在第二个集合中的行星,可以将行星名称投影为 second 集合并提供相同的 keySelector

// A shared "keySelector"
static string PlanetNameSelector(Planet planet) => planet.Name;

foreach (Planet planet in
    planets.ExceptBy(
        morePlanets.Select(PlanetNameSelector), PlanetNameSelector))
{
    Console.WriteLine(planet);
}

// This code produces the following output:
//     Planet { Name = Venus, Type = Rock, OrderFromSun = 2 }

在前述 C# 代码中:

  • keySelector 定义为 static 局部函数,用于区分行星名称。
  • 第一个行星阵列会根据名称筛选为第二个行星阵列中未找到的行星。
  • 将生成的 planet 实例写入控制台。

IntersectIntersectBy

以下示例演示 Enumerable.Intersect 的行为。 返回的序列包含两个输入序列共有的元素。

显示两个序列的交集的图。

string[] planets1 = { "Mercury", "Venus", "Earth", "Jupiter" };
string[] planets2 = { "Mercury", "Earth", "Mars", "Jupiter" };

IEnumerable<string> query = from planet in planets1.Intersect(planets2)
                            select planet;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * Mercury
 * Earth
 * Jupiter
 */

IntersectBy 方法是 Intersect 的替代方法,它采用可能是异构类型的两个序列和一个 keySelectorkeySelector 用作第二个集合类型的比较鉴别器。 请考虑以下行星阵列:

Planet[] firstFivePlanetsFromTheSun =
{
    Planet.Mercury,
    Planet.Venus,
    Planet.Earth,
    Planet.Mars,
    Planet.Jupiter
};

Planet[] lastFivePlanetsFromTheSun =
{
    Planet.Mars,
    Planet.Jupiter,
    Planet.Saturn,
    Planet.Uranus,
    Planet.Neptune
};

有两个行星阵列;一个代表来自太阳系的第五个行星,第二个代表来自太阳系的最后五个行星。 由于 Planet 类型是位置 record 类型,因此可以 keySelector 的形式使用它的值比较语义:

foreach (Planet planet in
    firstFivePlanetsFromTheSun.IntersectBy(
        lastFivePlanetsFromTheSun, planet => planet))
{
    Console.WriteLine(planet);
}

// This code produces the following output:
//     Planet { Name = Mars, Type = Rock, OrderFromSun = 4 }
//     Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 }

在前述 C# 代码中:

  • 这两个 Planet 阵列通过它们的值比较语义相交。
  • 只有在这两个阵列中都找到的行星才会出现在结果序列中。
  • 将生成的 planet 实例写入控制台。

UnionUnionBy

以下示例演示对两个字符串序列执行的联合操作。 返回的序列包含两个输入序列的唯一元素。

显示两个序列的并集的图。

string[] planets1 = { "Mercury", "Venus", "Earth", "Jupiter" };
string[] planets2 = { "Mercury", "Earth", "Mars", "Jupiter" };

IEnumerable<string> query = from planet in planets1.Union(planets2)
                            select planet;

foreach (var str in query)
{
    Console.WriteLine(str);
}

/* This code produces the following output:
 *
 * Mercury
 * Venus
 * Earth
 * Jupiter
 * Mars
 */

UnionBy 方法是 Union 的替代方法,它采用相同类型的两个序列和一个 keySelectorkeySelector 用作源类型的比较鉴别器。 请考虑以下行星阵列:

Planet[] firstFivePlanetsFromTheSun =
{
    Planet.Mercury,
    Planet.Venus,
    Planet.Earth,
    Planet.Mars,
    Planet.Jupiter
};

Planet[] lastFivePlanetsFromTheSun =
{
    Planet.Mars,
    Planet.Jupiter,
    Planet.Saturn,
    Planet.Uranus,
    Planet.Neptune
};

若要将这两个集合联合到一个序列中,请提供 keySelector

foreach (Planet planet in
    firstFivePlanetsFromTheSun.UnionBy(
        lastFivePlanetsFromTheSun, planet => planet))
{
    Console.WriteLine(planet);
}

// This code produces the following output:
//     Planet { Name = Mercury, Type = Rock, OrderFromSun = 1 }
//     Planet { Name = Venus, Type = Rock, OrderFromSun = 2 }
//     Planet { Name = Earth, Type = Rock, OrderFromSun = 3 }
//     Planet { Name = Mars, Type = Rock, OrderFromSun = 4 }
//     Planet { Name = Jupiter, Type = Gas, OrderFromSun = 5 }
//     Planet { Name = Saturn, Type = Gas, OrderFromSun = 6 }
//     Planet { Name = Uranus, Type = Liquid, OrderFromSun = 7 }
//     Planet { Name = Neptune, Type = Liquid, OrderFromSun = 8 }

在前述 C# 代码中:

  • 这两个 Planet 阵列使用它们的 record 值比较语义交织在一起。
  • 将生成的 planet 实例写入控制台。

请参阅