当前位置: 首页 > news >正文

C# Enumerable类 之 集合操作

总目录


前言

在 C# 中,System.Linq.Enumerable 类是 LINQ(Language Integrated Query)的核心组成部分,它提供了一系列静态方法,用于操作实现了 IEnumerable 接口的集合。通过这些方法,我们可以轻松地对集合进行查询、转换、排序和聚合等操作。

本文属于 C# Enumerable类 使用详解 中的一个章节,着重介绍 C# Enumerable 类中集合操作这部分的内容。


一、概览

方法描述示例
Concat序列合并(不去重)list1.Concat(list2);
UnionUnionBy序列并集(去重)list1.Union(list2);
ExceptExceptBy 序列差集list1.Except(list2);
IntersectIntersectBy 序列交集list1.Intersect(list2);

二、Concat :合并(不去重)

1. 什么是 Concat

Concat 是 LINQ 提供的一个扩展方法,用于将两个序列连接在一起,并返回一个包含所有元素的新序列。需要注意的是,Concat 方法不会去除重复项,如果需要去重可以使用 Union 方法。

2. Concat 方法 基本信息

1) Concat

public static IEnumerable<TSource> Concat<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second)
  • 参数
    • first:第一个要连接的序列。
    • second:第二个要连接的序列。
  • 返回值Concat 方法返回一个 IEnumerable<T> 对象,其中 T 是输入序列中元素的类型。

2)工作原理

Concat 方法通过惰性求值和迭代器模式,将两个序列依次遍历并返回一个新的序列,过程中不会创建新的集合对象,而是逐个返回两个序列中的元素。

3)使用场景

适用于合并多个集合、处理流式数据、数据预处理等场景。

3. 使用示例

示例 1:基本连接

假设我们有两个整数列表,我们希望将它们连接在一起形成一个新的列表。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int> { 4, 5, 6 };// 使用 Concat 连接两个列表var concatenatedList = list1.Concat(list2);Console.WriteLine(string.Join(",",concatenatedList));// 输出:1,2,3,4,5,6}
}

示例 2:不同类型的序列

虽然 Concat 方法要求两个序列的元素类型相同,但可以通过泛型和隐式转换来处理不同类型的数据。

class Program
{static void Main(){List<string> list1 = new List<string> { "Apple", "Banana" };List<object> list2 = new List<object> { 1, 2.5, true };// 使用 Concat 连接两个不同类型的列表var concatenatedList = list1.Cast<object>().Concat(list2);Console.WriteLine(string.Join(",",concatenatedList));// 输出:Apple,Banana,1,2.5,True}
}

示例 3:空序列

Concat 方法也可以用于将一个非空序列与一个空序列连接。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int>();// 使用 Concat 连接非空序列和空序列var concatenatedList = list1.Concat(list2);Console.WriteLine(string.Join(",",concatenatedList));// 输出:1,2,3}
}

示例 4:合并多个集合

当需要合并多个集合时,可以多次使用 Concat 方法,或者使用 Union 方法来去除重复项。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int> { 3, 4, 5, 6 };List<int> list3 = new List<int> { 6, 7, 8, 9 };// 使用 Concat 合并多个集合var concatenatedList = list1.Concat(list2).Concat(list3);Console.WriteLine(string.Join(",", concatenatedList));// 输出:1,2,3,3,4,5,6,6,7,8,9// 使用 Union 去除重复项var unionedList = list1.Union(list2).Union(list3);Console.WriteLine(string.Join(",", unionedList));// 输出:1,2,3,4,5,6,7,8,9}
}

示例 5:处理流式数据

由于 Concat 方法采用惰性求值,因此非常适合处理流式数据或无限序列。

class Program
{static void Main(){IEnumerable<int> streamData = GenerateStreamData();List<int> additionalData = new List<int> { 10, 20, 30 };// 使用 Concat 连接流式数据和附加数据var concatenatedStream = streamData.Concat(additionalData);// 输出结果Console.WriteLine("Concatenated Stream Data (First 10 elements):");foreach (var item in concatenatedStream.Take(10)){Console.Write(item + " ");}}static IEnumerable<int> GenerateStreamData(){int i = 0;while (true){yield return i++;}}
}

输出结果:

Concatenated Stream Data (First 10 elements):
0 1 2 3 4 5 6 7 8 9

示例 6:数据预处理

在某些情况下,你可能需要对数据进行预处理,然后再将其与其他数据连接起来。

using System;
using System.Collections.Generic;
using System.Linq;class Program
{static void Main(){List<int> rawData = new List<int> { 1, 2, 3, 4, 5 };List<int> processedData = rawData.Select(x => x * 2).ToList();List<int> additionalData = new List<int> { 10, 20, 30 };// 使用 Concat 连接预处理后的数据和其他数据var concatenatedData = processedData.Concat(additionalData);// 输出结果Console.WriteLine("Concatenated Data:");foreach (var item in concatenatedData){Console.Write(item + " ");}}
}

输出结果:

Concatenated Data:
2 4 6 8 10 10 20 30

4. 注意事项

尽管 Concat 方法非常有用,但在实际应用中也有一些需要注意的地方:

  • 空集合处理: 如果源集合为空,Concat 方法将返回一个空的结果集。因此,在使用 Concat 方法之前,通常不需要检查集合是否为空。
  • 数据类型一致:适用于需要合并的集合对象的数据类型是一样的情况。

三、UnionUnionBy:并集(去重)

在这里插入图片描述

1. 什么是 Union/UnionBy

  • Union 是 LINQ 提供的一个扩展方法,用于将两个序列合并成一个新的序列,并去除重复的元素。这个方法非常有用,特别是在需要合并多个集合并确保结果中没有重复项时。
  • UnionBy 是 .NET 6 及以上版本中引入的一个扩展方法,用于合并两个序列并根据指定的键选择器函数去除重复项。与 Union 方法不同的是,UnionBy 允许你通过一个自定义的键来确定元素是否相同,而不是直接比较整个对象。

2. Union/UnionBy 方法 基本信息

1) Union/UnionBy

public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
)public static IEnumerable<TSource> Union<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second,IEqualityComparer<TSource> comparer
)
  • 参数
    • first:第一个要合并的序列。
    • second:第二个要合并的序列。
    • comparer(可选):一个 IEqualityComparer<TSource> 实现,用于比较元素是否相等。
  • 返回值Union 方法返回一个 IEnumerable<T> 对象,其中 T 是输入序列中元素的类型。
public static IEnumerable<TSource> UnionBy<TSource, TKey>(this IEnumerable<TSource> first,IEnumerable<TSource> second,Func<TSource, TKey> keySelector
)public static IEnumerable<TSource> UnionBy<TSource, TKey>(this IEnumerable<TSource> first,IEnumerable<TSource> second,Func<TSource, TKey> keySelector,IEqualityComparer<TKey> comparer
)
  • 参数
    • first:第一个要合并的序列。
    • second:第二个要合并的序列。
    • keySelector:一个函数,用于从每个元素中提取键值。
    • comparer(可选):一个 IEqualityComparer 实现,用于比较键值是否相等。
  • 返回值UnionBy 方法返回一个 IEnumerable<TSource> 对象,其中 TSource 是输入序列中元素的类型。

2)工作原理

  • Union 方法通过惰性求值和迭代器模式,将两个序列合并成一个新的序列,并在遍历过程中自动去除重复元素。
  • UnionBy 方法通过指定的键选择器函数从两个序列中提取键值,并根据这些键值合并序列,去除重复项,最终返回一个包含唯一键值元素的新序列。

3)使用场景

适用于合并多个集合、处理流式数据、数据预处理、复杂数据结构合并等场景。

3. 使用示例

示例 1:基本合并

假设我们有两个整数列表,我们希望将它们合并在一起形成一个新的列表,并去除重复项。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int> { 3, 4, 5 };// 使用 Union 合并两个列表并去除重复项var unionedList = list1.Union(list2);Console.WriteLine(string.Join(",", unionedList));// 输出:1,2,3,4,5// 使用 UnionBy 合并两个列表并去除重复项unionedList = list1.UnionBy(list2, x => x);Console.WriteLine(string.Join(",", unionedList));// 输出:1,2,3,4,5}
}

在这个例子中,我们使用 Union / UnionBy 方法将两个整数列表合并在一起,并打印了结果。注意,数字 3 只出现了一次。

示例 2:自定义对象

当处理自定义对象时,Union 方法默认使用对象的 EqualsGetHashCode 方法来判断元素是否相同。如果你有更复杂的比较需求,可以提供自定义的 IEqualityComparer<T> 实现。

  • 使用默认的 EqualsGetHashCode 方法,并不能实现对象内容的比较
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}
class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Union 合并两个列表并去除重复项var unionedPeople = list1.Union(list2);Console.WriteLine(string.Join(",",unionedPeople));// 输出:Alice (30),Bob (25),Charlie (30),Bob (25)}
}
  • 重写 对象的 EqualsGetHashCode 方法,可以实现对象内容的比较。使用Union时,默认就会调用重写后的方法判断对象是否相等
class Person
{public string Name { get; set; }public int Age { get; set; }public override bool Equals(object obj){if (obj is Person other){return Name == other.Name && Age == other.Age;}return false;}public override int GetHashCode(){return HashCode.Combine(Name, Age);}public override string ToString(){return $"{Name} ({Age})";}
}
class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Union 合并两个列表并去除重复项var unionedPeople = list1.Union(list2);Console.WriteLine(string.Join(",",unionedPeople));// 输出:Alice (30),Bob (25),Charlie (30)}
}
  • 使用自定义的 PersonComparer 来比较 Person 对象,并确保合并后的结果中没有重复项。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}
class PersonComparer : IEqualityComparer<Person>
{public bool Equals(Person x, Person y){if (x == null || y == null) return false;return x.Name == y.Name && x.Age == y.Age;}public int GetHashCode(Person obj){return HashCode.Combine(obj.Name, obj.Age);}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{`在这里插入代码片`new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Union 合并两个列表并去除重复项var unionedPeople = list1.Union(list2,new PersonComparer());Console.WriteLine(string.Join(",",unionedPeople));// 输出:Alice (30),Bob (25),Charlie (30)}
}
  • 使用UnionBy ,通过指定键选择器函数来确定哪些对象应该被视为相同的。并确保合并后的结果中没有重复项。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 UnionBy 合并两个列表并根据年龄去重var unionedPeople = list1.UnionBy(list2, p => p.Age);Console.WriteLine(string.Join(",", unionedPeople));// 输出:Alice (30),Bob (25)}
}

示例 3:处理无限序列

Union /UnionBy方法采用惰性求值(Lazy Evaluation),这意味着它不会立即执行合并操作,而是等到实际遍历时才会计算结果。这使得 Union /UnionBy 可以处理无限序列或延迟执行复杂的查询。

using System;
using System.Collections.Generic;
using System.Linq;class Program
{static void Main(){IEnumerable<int> infiniteNumbers = Enumerable.Range(0, int.MaxValue).Select(i => i * 2);List<int> finiteNumbers = new List<int> { 1, 3, 5 };// 使用 Union 合并无限序列和有限序列var unionedSequence = infiniteNumbers.Union(finiteNumbers);// var unionedSequence = infiniteNumbers.UnionBy(finiteNumbers, x => x);// 限制输出数量Console.WriteLine("Unioned Sequence (First 10 elements):");foreach (var item in unionedSequence.Take(10)){Console.Write(item + " ");}}
}

输出结果:

Unioned Sequence (First 10 elements):
0 2 4 6 8 10 12 14 16 18

在这个例子中,我们展示了如何使用 Union /UnionBy 方法合并一个无限序列和一个有限序列,并通过 Take 方法限制输出的数量,从而避免无限循环。

示例 4:自定义比较器

当处理复杂的数据结构时,可以通过自定义比较器来实现更灵活的合并逻辑。

class Person
{public string Name { get; set; }public int Age { get; set; }public override bool Equals(object obj){if (obj is Person other){return Name == other.Name && Age == other.Age;}return false;}public override int GetHashCode(){return HashCode.Combine(Name, Age);}public override string ToString(){return $"{Name} ({Age})";}
}class PersonComparerByName : IEqualityComparer<Person>
{public bool Equals(Person x, Person y){if (x == null || y == null) return false;return x.Name == y.Name;}public int GetHashCode(Person obj){return obj.Name?.GetHashCode() ?? 0;}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Alice", Age = 31 },new Person { Name = "Charlie", Age = 30 }};// 使用 Union 合并两个列表并根据名字去重var unionedPeople = list1.Union(list2, new PersonComparerByName());Console.WriteLine(string.Join(",", unionedPeople));// 输出:Alice (30),Bob (25),Charlie (30)}
}

在这个例子中,我们展示了如何使用自定义的 PersonComparerByName 来根据名字去重合并 Person 对象。

class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class CustomAgeComparer : IEqualityComparer<int>
{public bool Equals(int x, int y){// 自定义比较逻辑:年龄相差不超过1岁视为相同return Math.Abs(x - y) <= 1;}public int GetHashCode(int obj){return 0;}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 26 }};// 使用 UnionBy 合并两个列表并根据年龄和自定义比较器去重var unionedPeople = list1.UnionBy(list2, p => p.Age, new CustomAgeComparer());Console.WriteLine(string.Join(",", unionedPeople));// 输出:Alice (30),Bob (25)}
}

示例 5:多个集合的合并

当需要合并多个集合时,可以多次使用 Union 方法。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3 };List<int> list2 = new List<int> { 4, 5, 6 };List<int> list3 = new List<int> { 7, 8, 9 };// 使用 Union 合并多个集合var unionedLists = list1.Union(list2).Union(list3);// var unionedLists = list1.UnionBy(list2, x => x).UnionBy(list3, x => x);Console.WriteLine(string.Join(",", unionedLists));// 输出:1,2,3,4,5,6,7,8,9}
}

4. 注意事项

尽管 Union/UnionBy 方法非常有用,但在实际应用中也有一些需要注意的地方:

  • 空集合处理: 如果源集合为空,Union/UnionBy 方法将返回一个空的结果集。因此,在使用 Union /UnionBy方法之前,通常不需要检查集合是否为空。
  • 数据类型一致:适用于需要合并的集合对象的数据类型是一样的情况。

四、ExceptExceptBy :差集

在这里插入图片描述

1. 什么是 Except/ExceptBy

  • Except 方法用于计算两个序列的差集,即返回第一个序列中存在但第二个序列中不存在的所有元素。默认情况下,它使用对象的默认比较器(如 EqualityComparer.Default)来比较元素是否相等。你也可以提供自定义的比较器来控制比较逻辑。
  • ExceptBy 是 .NET 6 及以上版本中引入的一个扩展方法,用于计算两个序列的差集,但与 Except 不同的是,它允许你通过指定的键选择器函数来确定元素是否相同。这意味着你可以根据某个特定属性或计算结果来进行差集操作,而不是直接比较整个对象。

2. Except/ExceptBy 方法 基本信息

1) Except/ExceptBy

public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
)public static IEnumerable<TSource> Except<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second,IEqualityComparer<TSource> comparer
)
  • 参数
    • first:第一个要计算差集的序列。
    • second:第二个要计算差集的序列。
    • comparer(可选):一个 IEqualityComparer<TSource> 实现,用于比较元素是否相等。
  • 返回值Except 方法返回一个 IEnumerable<TSource> 对象,其中 TSource 是输入序列中元素的类型。
public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first,IEnumerable<TKey> second,Func<TSource, TKey> keySelector
)public static IEnumerable<TSource> ExceptBy<TSource, TKey>(this IEnumerable<TSource> first,IEnumerable<TKey> second,Func<TSource, TKey> keySelector,IEqualityComparer<TKey> comparer
)
  • 参数
    • first:第一个要计算差集的序列。
    • second:第二个要计算差集的序列(注意这里的元素类型是键类型 TKey)。
    • keySelector:一个函数,用于从每个元素中提取键值。
    • comparer(可选):一个 IEqualityComparer 实现,用于比较键值是否相等。
  • 返回值UnionBy 方法返回一个 IEnumerable<TSource> 对象,其中 TSource 是输入序列中元素的类型。

2)工作原理

  • Except:计算两个序列的差集,返回第一个序列中存在但第二个序列中不存在的所有元素,并使用默认或自定义的比较器来判断元素是否相等。
  • ExceptBy:根据指定的键选择器函数提取键值,并计算两个序列的差集,返回第一个序列中存在但第二个序列中不存在的所有元素,去除具有相同键值的重复项。

3)使用场景

适用于数据过滤、数据预处理、多个集合的差集计算等场景。

3. 使用示例

示例 1:基本差集计算

假设我们有两个整数列表,我们希望计算第一个列表中存在但第二个列表中不存在的所有元素。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };List<int> list2 = new List<int> { 3, 4, 6 };// 使用 Except 计算差集var exceptList = list1.Except(list2);Console.WriteLine(string.Join(",", exceptList));// 输出:1,2,5exceptList = list1.ExceptBy(list2, x => x);Console.WriteLine(string.Join(",", exceptList));// 输出:1,2,5}
}

示例 2:自定义对象

当处理自定义对象时,Union 方法默认使用对象的 EqualsGetHashCode 方法来判断元素是否相同。如果你有更复杂的比较需求,可以提供自定义的 IEqualityComparer<T> 实现。

  • 使用默认的 EqualsGetHashCode 方法,并不能实现对象内容的比较
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};List<Person> list2 = new List<Person>{new Person { Name = "Bob", Age = 25 },new Person { Name = "David", Age = 40 }};// 使用 Except 计算差集var exceptPeople = list1.Except(list2);Console.WriteLine(string.Join(",", exceptPeople));// 输出:Alice (30),Bob (25),Charlie (35)}
}
  • 重写 对象的 EqualsGetHashCode 方法,可以实现对象内容的比较。使用Except时,默认就会调用重写后的方法判断对象是否相等
class Person
{public string Name { get; set; }public int Age { get; set; }public override bool Equals(object obj){if (obj is Person other){return Name == other.Name && Age == other.Age;}return false;}public override int GetHashCode(){return HashCode.Combine(Name, Age);}public override string ToString(){return $"{Name} ({Age})";}
}
class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Except 计算差集var exceptPeople = list1.Except(list2);Console.WriteLine(string.Join(",", exceptPeople));// 输出:Alice (30)}
}
  • 使用自定义的 PersonComparer 来比较 Person 对象。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}
class PersonComparer : IEqualityComparer<Person>
{public bool Equals(Person x, Person y){if (x == null || y == null) return false;return x.Name == y.Name && x.Age == y.Age;}public int GetHashCode(Person obj){return HashCode.Combine(obj.Name, obj.Age);}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Except 计算差集并使用自定义比较器var exceptPeople = list1.Except(list2, new PersonComparer());Console.WriteLine(string.Join(",", exceptPeople));// 输出:Alice (30)}
}
  • 使用ExceptBy ,通过指定键选择器函数来确定哪些对象应该被视为相同的。并确保合并后的结果中没有重复项。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};List<Person> list2 = new List<Person>{new Person { Name = "Bob", Age = 25 },new Person { Name = "David", Age = 40 }};// 使用 ExceptBy 计算差集并排除特定年龄var exceptPeople = list1.ExceptBy(list2.Select(x => x.Age), p => p.Age);Console.WriteLine(string.Join(",", exceptPeople));// 输出:Alice (30),Charlie (35)}
}

示例 3:处理无限序列

Except /ExceptBy方法采用惰性求值(Lazy Evaluation),这意味着它不会立即执行合并操作,而是等到实际遍历时才会计算结果。这使得 Except /ExceptBy 可以处理无限序列或延迟执行复杂的查询。

class Program
{static void Main(){IEnumerable<int> infiniteNumbers = Enumerable.Range(0, int.MaxValue).Select(i => i * 2);List<int> finiteNumbers = new List<int> { 1, 3, 5 };// 使用 Union 合并无限序列和有限序列//var unionedSequence = infiniteNumbers.Except(finiteNumbers);var unionedSequence = infiniteNumbers.ExceptBy(finiteNumbers, x => x);// 限制输出数量Console.WriteLine("Unioned Sequence (First 10 elements):");foreach (var item in unionedSequence.Take(10)){Console.Write(item + " ");}}
}

输出结果:

Unioned Sequence (First 10 elements):
0 2 4 6 8 10 12 14 16 18

在这个例子中,我们展示了如何使用 Except /ExceptBy 方法合并一个无限序列和一个有限序列,并通过 Take 方法限制输出的数量,从而避免无限循环。

示例 4:自定义比较器

class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class CustomAgeComparer : IEqualityComparer<int>
{public bool Equals(int x, int y){// 自定义比较逻辑:年龄相差不超过1岁视为相同return Math.Abs(x - y) <= 1;}public int GetHashCode(int obj){return 0;}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 26 }};// 使用 UnionBy 合并两个列表并根据年龄和自定义比较器去重var unionedPeople = list1.ExceptBy(list2.Select(x=>x.Age), p => p.Age, new CustomAgeComparer());Console.WriteLine(string.Join(",", unionedPeople));// 输出:Charlie (35)}
}

示例 5:多个集合的合并

当需要合并多个集合时,可以多次使用 Except/ExceptBy 方法。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };List<int> list2 = new List<int> { 3, 4, 6 };List<int> list3 = new List<int> { 4, 7, 8 };// 使用 Union 合并多个集合//var unionedLists = list1.Except(list2).Except(list3);var unionedLists = list1.ExceptBy(list2, x => x).ExceptBy(list3, x => x);Console.WriteLine(string.Join(",", unionedLists));// 输出:1,2,5}
}

4. 注意事项

尽管 Except/ExceptBy 方法非常有用,但在实际应用中也有一些需要注意的地方:

  • 空集合处理: 如果源集合为空,Except/ExceptBy 方法将返回一个空的结果集。因此,在使用 Except /ExceptBy 方法之前,通常不需要检查集合是否为空。
  • 数据类型一致:适用于需要取差集的集合对象的数据类型是一样的情况。

五、IntersectIntersectBy :交集

在这里插入图片描述

1. 什么是 Intersect/IntersectBy

  • Intersect 方法用于计算两个序列的交集,即返回两个序列中共有的所有元素。默认情况下,它使用对象的默认比较器(如 EqualityComparer<T>.Default)来比较元素是否相等。你也可以提供自定义的比较器来控制比较逻辑。
  • IntersectBy 是 .NET 6 及以上版本中引入的一个扩展方法,用于计算两个序列的交集,但与 Intersect 不同的是,它允许你通过指定的键选择器函数来确定元素是否相同。这意味着你可以根据某个特定属性或计算结果来进行交集操作,而不是直接比较整个对象。

2. Intersect/IntersectBy 方法 基本信息

1) Intersect/IntersectBy

public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second
)public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first,IEnumerable<TSource> second,IEqualityComparer<TSource> comparer
)
  • 参数
    • first:第一个要计算交集的序列。
    • second:第二个要计算交集的序列。
    • comparer(可选):一个 IEqualityComparer<TSource> 实现,用于比较元素是否相等。
  • 返回值Except 方法返回一个 IEnumerable<TSource> 对象,其中 TSource 是输入序列中元素的类型。
public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first,IEnumerable<TKey> second,Func<TSource, TKey> keySelector
)public static IEnumerable<TSource> IntersectBy<TSource, TKey>(this IEnumerable<TSource> first,IEnumerable<TKey> second,Func<TSource, TKey> keySelector,IEqualityComparer<TKey> comparer
)
  • 参数
    • first:第一个要计算交集的序列。
    • second:第二个要计算交集的序列(注意这里的元素类型是键类型 TKey)。
    • keySelector:一个函数,用于从每个元素中提取键值。
    • comparer(可选):一个 IEqualityComparer 实现,用于比较键值是否相等。
  • 返回值UnionBy 方法返回一个 IEnumerable<TSource> 对象,其中 TSource 是输入序列中元素的类型。

2)工作原理

  • Intersect:计算两个序列的交集,返回两个序列中共有的所有元素,并使用默认或自定义的比较器来判断元素是否相等。
  • IntersectBy:根据指定的键选择器函数提取键值,并计算两个序列的交集,返回第一个序列中具有与第二个序列中相同键值的所有元素。

3)使用场景

适用于数据过滤、数据预处理、多个集合的交集计算等场景。

3. 使用示例

示例 1:基本交集计算

假设我们有两个整数列表,我们希望找出它们共有的元素。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };List<int> list2 = new List<int> { 3, 4, 6 };// 使用 Intersect 计算交集var intersectList = list1.Intersect(list2);Console.WriteLine(string.Join(",", intersectList));// 输出:3,4intersectList = list1.IntersectBy(list2, x => x);Console.WriteLine(string.Join(",", intersectList));// 输出:3,4}
}

示例 2:自定义对象

当处理自定义对象时,Intersect 方法默认使用对象的 EqualsGetHashCode 方法来判断元素是否相同。如果你有更复杂的比较需求,可以提供自定义的 IEqualityComparer<T> 实现。

  • 使用默认的 EqualsGetHashCode 方法,并不能实现对象内容的比较
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};List<Person> list2 = new List<Person>{new Person { Name = "Bob", Age = 25 },new Person { Name = "David", Age = 40 }};// 使用 Intersect 计算交集var intersectPeople = list1.Intersect(list2);Console.WriteLine(string.Join(",", intersectPeople));// 输出:          - 表示 没有交集}
}
  • 重写 对象的 EqualsGetHashCode 方法,可以实现对象内容的比较。使用Except时,默认就会调用重写后的方法判断对象是否相等
class Person
{public string Name { get; set; }public int Age { get; set; }public override bool Equals(object obj){if (obj is Person other){return Name == other.Name && Age == other.Age;}return false;}public override int GetHashCode(){return HashCode.Combine(Name, Age);}public override string ToString(){return $"{Name} ({Age})";}
}
class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Intersect 计算交集var intersectPeople = list1.Intersect(list2);Console.WriteLine(string.Join(",", intersectPeople));// 输出:Bob (25)}
}
  • 使用自定义的 PersonComparer 来比较 Person 对象。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}
class PersonComparer : IEqualityComparer<Person>
{public bool Equals(Person x, Person y){if (x == null || y == null) return false;return x.Name == y.Name && x.Age == y.Age;}public int GetHashCode(Person obj){return HashCode.Combine(obj.Name, obj.Age);}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "Bob", Age = 25 }};// 使用 Intersect 计算交集并使用自定义比较器var intersectPeople = list1.Intersect(list2, new PersonComparer());Console.WriteLine(string.Join(",", intersectPeople));// 输出:Bob (25)}
}
  • 使用ExceptBy ,通过指定键选择器函数来确定哪些对象应该被视为相同的。并确保合并后的结果中没有重复项。
class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};List<Person> list2 = new List<Person>{new Person { Name = "Bob", Age = 25 },new Person { Name = "David", Age = 40 }};// 使用 IntersectBy 计算交集var intersectPeople = list1.IntersectBy(list2.Select(x => x.Age), p => p.Age);Console.WriteLine(string.Join(",", intersectPeople));// 输出:Bob (25)}
}

示例 3:处理无限序列

Intersect /IntersectBy方法采用惰性求值(Lazy Evaluation),这意味着它不会立即执行合并操作,而是等到实际遍历时才会计算结果。这使得 Intersect /IntersectBy 可以处理无限序列或延迟执行复杂的查询。

class Program
{static void Main(){IEnumerable<int> infiniteNumbers = Enumerable.Range(0, int.MaxValue).Select(i => i * 2);List<int> finiteNumbers = new List<int> { 4, 6, 8 };// 使用 Intersect 计算交集var intersectSequence = infiniteNumbers.Intersect(finiteNumbers);// 限制输出数量Console.WriteLine("Elements common between infiniteNumbers and finiteNumbers (First 3 elements):");foreach (var item in intersectSequence.Take(3)){Console.Write(item + " ");}}
}

输出结果:

Elements common between infiniteNumbers and finiteNumbers (First 3 elements):
4 6 8

在这个例子中,我们展示了如何使用 Intersect 方法计算一个无限序列和一个有限序列之间的交集,并通过 Take 方法限制输出的数量,从而避免无限循环。

示例 4:自定义比较器

class Person
{public string Name { get; set; }public int Age { get; set; }public override string ToString(){return $"{Name} ({Age})";}
}class CustomAgeComparer : IEqualityComparer<int>
{public bool Equals(int x, int y){// 自定义比较逻辑:年龄相差不超过1岁视为相同return Math.Abs(x - y) <= 1;}public int GetHashCode(int obj){return 0;}
}class Program
{static void Main(){List<Person> list1 = new List<Person>{new Person { Name = "Alice", Age = 30 },new Person { Name = "Bob", Age = 25 },new Person { Name = "Charlie", Age = 35 }};List<Person> list2 = new List<Person>{new Person { Name = "Charlie", Age = 30 },new Person { Name = "David", Age = 26 }};// 使用 IntersectBy 取两个列表交集并根据年龄和自定义比较器 比较Person对象var intersectPeople = list1.IntersectBy(list2.Select(x => x.Age), p => p.Age, new CustomAgeComparer());Console.WriteLine(string.Join(",", intersectPeople));// 输出:Alice (30),Bob (25)}
}

示例 5:多个集合的合并

当需要合并多个集合时,可以多次使用 Intersect/IntersectBy 方法。

class Program
{static void Main(){List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };List<int> list2 = new List<int> { 3, 4, 6 };List<int> list3 = new List<int> { 4, 7, 8 };// 使用 Union 合并多个集合//var unionedLists = list1.Intersect(list2).Intersect(list3);var unionedLists = list1.IntersectBy(list2, x => x).IntersectBy(list3, x => x);Console.WriteLine(string.Join(",", unionedLists));// 输出:4}
}

4. 注意事项

尽管 Intersect/IntersectBy方法非常有用,但在实际应用中也有一些需要注意的地方:

  • 空集合处理: 如果源集合为空, Intersect/IntersectBy 方法将返回一个空的结果集。因此,在使用 Intersect/IntersectBy方法之前,通常不需要检查集合是否为空。
  • 数据类型一致:适用于需要取差集的集合对象的数据类型是一样的情况。

结语

回到目录页:C#/.NET 知识汇总
希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
微软官方文档 Enumerable

相关文章:

C# Enumerable类 之 集合操作

总目录 前言 在 C# 中&#xff0c;System.Linq.Enumerable 类是 LINQ&#xff08;Language Integrated Query&#xff09;的核心组成部分&#xff0c;它提供了一系列静态方法&#xff0c;用于操作实现了 IEnumerable 接口的集合。通过这些方法&#xff0c;我们可以轻松地对集合…...

LVGL移植到6818开发板

一、移植步骤 1.lv_config.h 配置文件启动 framebuffer 2、lv_config.h 配置文件关闭SDL 2.修改main.c 去掉SDL输入设备 3.修改Makefile 文件启动交叉编译 去掉警告参数 去掉SDL库 4.交叉编译代码 make clean #清空 ⭐ 必须要清空一次再编译&#xff01; 因为修改了 lv_con…...

深入理解 `ParameterizedTypeReference`:解决 Java 泛型擦除问题

在 Java 中&#xff0c;由于类型擦除的存在&#xff0c;我们在使用 RestTemplate 获取带有泛型的 HTTP 响应时&#xff0c;可能会遇到 泛型信息丢失 的问题。而 ParameterizedTypeReference<T> 正是用来解决这个问题的。 本文将深入解析 ParameterizedTypeReference 的作…...

如何使用Python的matplotlib.pyplot绘制热图和损失图

在Python的数据可视化中&#xff0c;matplotlib是一个非常重要的库。而matplotlib.pyplot作为其中一个模块&#xff0c;提供了许多绘制各种图形的函数。今天&#xff0c;我们就来聊聊如何利用这个库来绘制热图和损失图&#xff0c;通过这两个图形展示数据&#xff0c;让我们一起…...

【数据分享】2000—2024年我国省市县三级逐月归一化植被指数(NDVI)数据(Shp/Excel格式)

之前我们分享过2000—2024年逐月归一化植被指数&#xff08;NDVI&#xff09;栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;&#xff0c;该数据来源于NASA定期发布的MOD13A3数据集&#xff01;很多小伙伴拿到数据后反馈栅格数据不太方便使用&#xff0c;问我们能不…...

数据结构---堆栈和列

一、堆栈 1.栈堆&#xff1a;具有一定操作约束的线性表&#xff1b;&#xff08;只在一端做插入删除&#xff09; 2.栈的顺序存储结构&#xff1a; 由一个一维数组和一个记录栈顶元素位置的变量组成。定义方式如下&#xff1a; 3.入栈操作&#xff1a; 注意&#xff1a;&…...

威胁驱动的网络安全方法论

摘要 目前的网络安全风险管理实践很大程度上是由合规性要求驱动的&#xff0c;这使得公司/组织不得不在安全控制和漏洞上投入人力/物力。&#xff08;风险管理涉及多个方面&#xff0c;包括资产、威胁、漏洞和控制&#xff0c;并根据事故发生的可能性及造成的影响进行评估。威胁…...

搭建Spring Boot Admin监控系统

什么是Spring Boot Admin Spring Boot Admin 是一个用于管理和监控 Spring Boot 应用程序的开源工具。它提供了一个用户友好的 Web 界面&#xff0c;用于集中管理和监控多个 Spring Boot 应用程序的运行状态、健康状况、日志、配置等信息。 Spring Boot Admin 的核心功能 应用…...

P2730 魔板 (写了巨久..有一些数字,字符,字符串之间的转换规则)

ac代码&#xff1a; #include<iostream> #include<map> #include<queue> using namespace std; map<string,int>mp1,mp2; map<string,string>mp3; queue<string>q; string str,res"12345678"; void pri(string str){if(resstr)…...

MinIo前后端实现

这几天想玩玩Minio&#xff0c;整体来说简单使用起来不复杂&#xff08;当然也有可能是我配置的太少了&#xff09; Minio下载 我是通过Dokcer在虚拟机上下载的&#xff08;Docker真好用啊&#xff09; 拉取Minio镜像 docker pull minio/minio启动Minio容器 docker run -d …...

mesh开发解析

开源的Mesh网络协议栈及相关项目&#xff1a; 1.B.A.T.M.A.N.(Better Approach to Mobile Ad-hoc Networking)• 简介&#xff1a;B.A.T.M.A.N.是一种用于多跳自组织网络的路由协议&#xff0c;适用于无线Mesh网络。它通过优化数据传输路径&#xff0c;确保网络的高可靠性和动…...

使用netlify部署github的vue/react项目或本地的dist,国内也可以正常访问

提供简洁的部署流程和丰富功能&#xff0c;如自定义域名、自动构建和服务器端功能。通过连接到 Git 仓库实现持续部署&#xff0c;每次推送代码都会自动构建和发布&#xff0c;支持无服务器函数&#xff0c;允许在前端项目中实现后端逻辑&#xff0c;提供直观的用户界面来管理和…...

LinuX---Shell正则表达式

正则表达式 正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文本编辑器里&#xff0c;正则表达式通常被用来检索、替换那些符合某个模式的文本。在Linux中&#xff0c;grep&#xff0c;sed&#xff0c;awk等命令都支持通过正则表达式进行模式匹配…...

[Hello-CTF]RCE-Labs超详细WP-Level10(无字母命令执行_二进制整数替换)

温馨提示 这关涉及的知识点较多, 写的很长, 中间留了很多错误引导(本人在实验时遇到的问题, 或许你们也会遇到), 在后文才逐步解释源码分析 跟前几关一样, 更改了 WAF 的过滤字段这个关卡, 只有0, 1, (单引号), $, <, \ , ( , )可以用解题分析(实验这些命令, 可以先在自己本…...

基于PySide6与CATIA Automation的批量截图处理系统开发实践

引言 本文完整实现了基于PySide6 GUI框架与CATIA Automation技术的批量截图处理系统。系统支持对CATIA文件&#xff08;.CATPart/.CATProduct&#xff09;的自动化截图、图像优化及批量导出&#xff0c;通过模块化架构设计实现了超过200%的效率提升。本文将从技术架构、核心算…...

AI开发软件:开启智能时代的钥匙

在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;已不再是一个遥远的概念&#xff0c;而是深入到我们生活和工作的方方面面&#xff0c;成为推动各行业变革与发展的核心力量。AI 开发软件作为实现人工智能技术落地的关键工具&#xff0c;正引领着一场前所未有的…...

73.HarmonyOS NEXT PicturePreviewImage组件深度剖析:高级功能扩展与性能优化策略(三)

温馨提示&#xff1a;本篇博客的详细代码已发布到 git : https://gitcode.com/nutpi/HarmonyosNext 可以下载运行哦&#xff01; HarmonyOS NEXT PicturePreviewImage组件深度剖析&#xff1a;高级功能扩展与性能优化策略(三) 文章目录 HarmonyOS NEXT PicturePreviewImage组件…...

【模拟算法】

目录 替换所有的问号 提莫攻击 Z 字形变换 外观数列 数青蛙&#xff08;较难&#xff09; 模拟算法&#xff1a;比葫芦画瓢。思路较简单&#xff0c;考察代码能力。 1. 模拟算法流程&#xff0c;一定要在演草纸上过一遍流程 2. 把流程转化为代码 替换所有的问号 1576. 替…...

Spring Cloud 中的服务注册与发现: Eureka详解

1. 背景 1.1 问题描述 我们如果通过 RestTamplate 进行远程调用时&#xff0c;URL 是写死的&#xff0c;例如&#xff1a; String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 当机器更换或者新增机器时&#xff0c;这个 URL 就需要相应地变…...

WireShark自动抓包

背景 异常流量检测是当前保护网络空间安全的重要检测方法。 对流量的研究&#xff0c;首先需要在系统中进行抓包&#xff0c;并对包进行分析。 这里对WireShark自动抓包进行简要介绍。 操作步骤 1、选择“捕获”>“选项”。 2、在Input下&#xff0c;选择要抓包的网络接…...

Redis 的应用场景

缓存&#xff1a; 作为缓存层&#xff0c;加速数据访问&#xff0c;减轻数据库压力&#xff0c;常用于网页、数据库查询结果的缓存。 会话存储&#xff1a; 存储用户会话信息&#xff0c;支持分布式系统中的会话共享。 消息队列&#xff1a; 利用列表和发布/订阅功能&#xf…...

React使用路由表

目录 前言 实现步骤 1. 安装依赖 2. 创建路由配置文件 高级配置 嵌套路由配置 对比两种配置方式 传统 JSX 方式 路由表方式优势 完整功能示例 带路由守卫的配置 注意事项 总结 前言 React Router 从 v6 版本开始支持类似 Vue 的集中式路由表配置方式&#xff0c;通…...

嵌入式C语言中堆栈管理与数据存储的精髓

在嵌入式开发中,理解C语言的内存管理和数据存储机制是至关重要的。本文将从堆栈管理和数据存储两个方面,深入探讨C语言在嵌入式Linux开发中的应用。 一、堆栈管理 1.1 栈的初始化与作用 栈是C语言运行的基础,主要用于存储函数参数、局部变量、函数返回值和编译器生成的临时…...

Linux系统之less命令的基本使用

Linux系统之less命令的基本使用 一、less命令介绍二、less命令的使用帮助2.1 less命令的帮助信息2.2 less命令主要选项解释 三、less命令的基本使用3.1 查看文件内容3.2 结合管道使用 四、注意事项 一、less命令介绍 在Linux和Unix类操作系统中&#xff0c;文件浏览是一项常见的…...

【免费】1949-2020年各省人均GDP数据

1949-2020年各省人均GDP数据 1、时间&#xff1a;1952-2020年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;各省人均GDP 4、范围&#xff1a;31省 5、指标解释&#xff1a;人均GDP&#xff08;Gross Domestic Product per capita&#xff09;是指一个国家…...

三分钟掌握视频剪辑 | 在 Rust 中优雅地集成 FFmpeg

前言 在当今的短视频时代&#xff0c;高效的视频剪辑已成为内容创作者和开发者的迫切需求。无论是裁剪视频开头结尾、提取高光时刻&#xff0c;还是制作 GIF、去除广告&#xff0c;剪辑都是必不可少的一环。 然而&#xff0c;批量处理大量视频并非易事&#xff0c;常见的挑战…...

angular中下载接口返回文件

目录 一、URL.createObjectURL() 一、URL.createObjectURL() createObjectURL属于js的原生方法&#xff0c;位于window.URL上&#xff0c;用于将Blob或者File文件转换为可以临时的URL地址进行显示 **注意**&#xff1a;Angular 的 HttpClient 默认将响应解析为 JSON 对象‌16。…...

自定义tiptap插件

本文为开发开源项目的真实开发经历&#xff0c;感兴趣的可以来给我的项目点个star&#xff0c;谢谢啦~ 具体博文介绍&#xff1a; 开源&#xff5c;Documind协同文档&#xff08;接入deepseek-r1、支持实时聊天&#xff09;Documind &#x1f680; 一个支持实时聊天和接入 - 掘…...

爬虫基础之爬取豆瓣同城信息(保存为csv excel 数据库)

网站:长沙最近一周戏剧活动_豆瓣 温馨提示: 本案例仅供学习交流使用 本案例所使用的模块 requests(发送HTTP请求)pandas(数据保存模块)lxml(用于解析数据模块)csv(用于保存为csv文件)pymysql(用于操作数据库)parsel(解析数据的模块) 确定爬取的信息内容&#xff1a; 戏剧的名称…...

MongoDB Vs Elasticsearch

文章目录 前言一、核心区别二、优缺点MongoDBElasticsearch 三、如何选择四、结合使用总结 前言 MongoDB 和 Elasticsearch 在存储、查询方式、使用场景等方面有较大区别&#xff0c;以下是它们的核心区别、各自优缺点以及实际使用中的选择建议。 一、核心区别 对比项MongoDB…...

《蓝耘容器全栈技术指南:企业级云原生与异构计算实战大全》

在数字化转型的浪潮中&#xff0c;容器技术已成为企业构建云原生架构的核心引擎&#xff0c;而蓝耘容器凭借其轻量化内核、异构计算支持及混合云调度能力&#xff0c;正成为企业级应用的首选方案。本文基于《蓝耘容器全栈技术指南》&#xff0c;结合实战案例与技术原理&#xf…...

【Android】RuntimeShader 应用

1 简介 RuntimeShader 是 Android 13&#xff08;T&#xff09;中新增的特性&#xff0c;用于逐像素渲染界面&#xff0c;它使用 AGSL&#xff08;Android Graphics Shading Language&#xff09;编写着色器代码&#xff0c;底层基于 Skia 图形渲染引擎。官方介绍详见 → Runti…...

python 提取视频中的音频

在Python中提取视频中的音频&#xff0c;你可以使用moviepy库&#xff0c;这是一个非常强大且易于使用的库&#xff0c;专门用于视频编辑。以下是如何使用moviepy来提取视频中的音频的步骤&#xff1a; 安装moviepy 首先&#xff0c;你需要安装moviepy。你可以通过pip安装它&a…...

HTML+CSS基础(了解水平)

html 的介绍 学习目标 能够知道html的作用 1. html的定义 2. html的定义 HTML 的全称为&#xff1a;HyperText Mark-up Language, 指的是超文本标记语言。 标记&#xff1a;就是标签, <标签名称> </标签名称>, 比如: <html></html>、<h1><…...

提示词工程(Prompt Engineering)

https://www.bilibili.com/video/BV1PX9iYQEry 一、懂原理&#xff0c;要知道 为什么有的指令有效&#xff0c;有的指令无效为什么同样的指令有时有效&#xff0c;又是无效怎么提升指令有效的概率 大模型应用架构师想什么&#xff1f; 怎样能更准确&#xff1f;答&#xff1…...

MySQL中的B+树索引经验总结

一、什么是B树 B树是一种二叉树&#xff0c;由二叉查找树&#xff0c;平衡二叉树&#xff0c;B树演化而来。 请看上图 B树的特点&#xff1a; 1&#xff09;非叶子节点不存放数据&#xff0c;只存放键值&#xff0c;数据都存放在叶子节点中。 2&#xff09;叶子节点都在同一…...

社交网络分析实战(NetworkX分析Twitter关系图)

目录 社交网络分析实战(NetworkX分析Twitter关系图)1. 引言2. 项目背景与意义3. 数据集生成与介绍3.1 数据集构成3.2 数据生成方法3.3 数据集示例4. 社交网络分析理论4.1 节点度数与度分布4.2 网络密度4.3 中心性指标5. GPU加速在社交网络分析中的应用6. PyQt GUI与交互式可视…...

Windows功能之FTP服务器搭建

一、创作背景 之前有用linux系统搭建过ftp服务器&#xff0c;最近想着用windows系统也顺便搭建一个&#xff0c;看网上有第三方服务软件一键部署&#xff0c;记得windows可以不借助第三方软件就可以搭建&#xff0c;就想顺便操作试试&#xff0c;结果老是连接不上&#xff0c;费…...

linux系统命令——权限

一、有哪些权限 读&#xff08;r&#xff09;——对应数字4 写&#xff08;w&#xff09;——对应数字2 执行&#xff08;x&#xff09;——对应数字1 二、权限及数字的对应 4对应r-- 2对应-w- 1对应--x 5对应r-x 6对应rw- 7对应rwx 三、文件的基本属性 如图&#…...

DeepSeek本地部署 (Windows+Ollama+Docker Desktop+ RAGFlow)

适用场景&#xff1a; 1、商城的小机器人自动根据实际情况回复 2、需要7*24小时运行在线回复&#xff0c;如&#xff1a;在线购物、在线咨询、在线招生等 3、无人值守环境 2025年1月&#xff0c;DeepSeek 正式发布 DeepSeek-R1 推理大模型&#xff0c;DeepSeek-R1 成本价格低…...

H3C无线控制器二层注册典型配置举例

介绍AP与AC间通过二层网络完成注册的配置举例 组网需求 如图所示&#xff0c;集中式转发架构下&#xff0c;AC旁挂在L2 switch1上&#xff0c;L3 switch做DHCP server为AP、Client和Host分配IP地址。需要实现无线客户端Client通过AP连接到AC上&#xff0c;并能与有线客户端Hos…...

前端面试笔试

前端面试笔试 1 相对路径和绝对路径的区别 区别&#xff1a;他们描述文件或目录位置的方式不同 ‌绝对路径‌&#xff1a;绝对路径是指从系统的根目录开始的完整路径&#xff0c;无论当前工作目录在哪个位置&#xff0c;绝对路径始终指向文件或目录的确切位置。绝对路径适用…...

java的split分隔,使用regex

split(String regex) 是 Java 中 String 类的一个方法&#xff0c;用于根据正则表达式&#xff08;regex&#xff09;将字符串分割为子字符串数组。以下是一些常用的正则表达式及其用途&#xff1a; 按空格分割 正则表达式&#xff1a;“\s” 作用&#xff1a;匹配一个或多个…...

写时拷贝技术

目录 写时拷贝 核心思想 基本原理 基本过程 一个例子深入理解 补充知识--引用计数 小总结 写时拷贝实现 宏观理解&#xff08;进程、线程角度&#xff09; 资源共享 只读访问 写操作触发拷贝 独立修改 微观理解&#xff08;fork系统调用角度&#xff09; 进程创…...

HarmonyOS NEXT开发进阶(十二):build-profile.json5 文件解析

文章目录 一、前言二、Hvigor脚本文件三、任务与任务依赖图四、多模块管理4.1 静态配置模块 五、分模块编译六、配置多目标产物七、配置APP多目标构建产物八、定义 product 中包含的 target九、拓展阅读 一、前言 编译构建工具DevEco Hvigor&#xff08;以下简称Hvigor&#x…...

ubuntu系统下添加pycharm到快捷启动栏方法

一、背景 之前在ubuntu系统下使用pycharm时&#xff0c;总是要进入/home/dlut/pycharm-community-2022.1/bin文件夹下&#xff0c;然后终端执行命令下面的命令才可修改代码&#xff1a; ./pycharm.sh为了以后方便&#xff0c;这里给出添加pycharm到快捷启动栏的方法 二、添加…...

简述计算机网络中的七层模型和四层模型

在计算机网络中&#xff0c;网络协议栈的设计通常采用分层结构来处理不同的通信任务。常见的分层结构有OSI七层模型和TCP/IP四层模型。虽然它们的层次数量不同&#xff0c;但本质上都在解决如何有效地进行计算机间通信。本文将分别介绍这两种结构的功能和各层的协议。 一、OSI七…...

golang开发支持onlyoffice的token功能

一直都没去弄token这块&#xff0c;想着反正docker run的时候将jwt置为false即可。 看了好多文章&#xff0c;感觉可以试试&#xff0c;但是所有文件几乎都没说思路。 根据我的理解和成功的调试&#xff0c;思路是&#xff1a; 我们先定义2个概念&#xff0c;一个是文档下载…...

【Linux】:封装线程

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家带来封装线程相关的知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通 数据结…...

OpenCV多分辨率模板匹配与容错优化实战指南

第一章&#xff1a;问题背景与挑战 1.1 传统模板匹配的局限性 模板匹配&#xff08;Template Matching&#xff09;是计算机视觉中基础且广泛使用的技术&#xff0c;其核心思想是通过滑动窗口在目标图像中寻找与模板最相似的位置。然而&#xff0c;传统方法&#xff08;如Ope…...