合并 2 个奇数和偶数数组并使用 TASK 操作显示为自然数
Merge 2 arrays with Odd and Even numbers and display as Natural Numbers with TASK Operation
假设我们有 2 个异步方法
public async Task<int[]> GetOddNumbers()
{
return new int[] { 1, 3, 5, 7, 9 };
}
public async Task<int[]> GetEvenNumbers()
{
return new int[] { 2, 4, 6, 8, 10 };
}
我想将数组和显示合并为 1,2,3,4,5,6,7,8,9,10
。
我们如何通过 C# 中的 TAP(基于任务的异步模式)实现这一点?
请大家帮忙提宝贵意见
您当前的实现不需要任何异步代码。
我想这只是一个简化的示例,所以我将它们视为异步方法。
static async Task Main(string[] args)
{
var odds = await GetOddNumbers();
var evens = await GetEvenNumbers();
var numbers = (odds).Zip(evens)
.SelectMany(tuple => new [] { tuple.First, tuple.Second });
Console.ReadLine();
}
- 我们检索两个集合。
- 我们将
odds
中的一个元素组合 (Zip
) 到 evens
中的另一个元素。所以,我们最终会得到以下结构(元组数组):
[
(1,2),
(3,4),
(5,6),
(7,8),
(9,10),
]
- 为了将其展平,我们需要调用
SelectMany
。您可以通过 First
属性 访问左侧项目,通过 Second
属性.
访问右侧项目
3.1) 如果你只调用 Select
而不是 SelectMany
那么你最终会得到一个数组数组。
[
[1,2],
[3,4],
[5,6],
[7,8],
[9,10],
]
3.2) 但是使用 SelectMany
我们将数组的数组展平为一个简单的数组。
[
1,2,3,4,5,6,7,8,9,10
]
更新:OP 添加了一项新要求(作为注释),即数据应 one-by-one 和异步检索。
为了满足这个我们需要使用IAsyncEnumerable<T>
。这使我们能够在可用时一次提供一个数据。
提供商方
因此,我们必须 return 和 IAsyncEnumerable<int>
而不是 returning Task<int[]>
。 GetOddNumbers
和 GetEvenNumbers
可以这样重写:
public static async IAsyncEnumerable<int> GetOddNumbers()
{
var odds = new int[] { 1, 3, 5, 7, 9 };
foreach (var odd in odds)
{
await Task.Delay(1000); //Whatever async method call
yield return odd;
}
}
public static async IAsyncEnumerable<int> GetEvenNumbers()
{
var evens = new int[] { 2, 4, 6, 8, 10 };
foreach (var even in evens)
{
await Task.Delay(1000); //Whatever async method call
yield return even;
}
}
消费端
我们可以利用 C# 8 新的 await foreach
关键字。IAsyncEnumerable 没有 built-in Zip
函数,所以我们需要使用自定义的,像这样: async-enumerable-dotnet
有了这些,Main
方法将如下所示:
static async Task Main(string[] args)
{
var toBeIterated = async_enumerable_dotnet.AsyncEnumerable.Zip(z => z, GetOddNumbers(), GetEvenNumbers());
await foreach (int[] oddEvenPair in toBeIterated)
{
Console.WriteLine(oddEvenPair[0]);
Console.WriteLine(oddEvenPair[1]);
}
Console.WriteLine("Finished");
Console.ReadLine();
}
它将一次打印出一对数据,然后在下一对之间等待一秒钟。
{1 sec wait}
1
2
{1 sec wait}
3
4
{1 sec wait}
5
6
{1 sec wait}
7
8
{1 sec wait}
9
10
Finished
假设我们有 2 个异步方法
public async Task<int[]> GetOddNumbers()
{
return new int[] { 1, 3, 5, 7, 9 };
}
public async Task<int[]> GetEvenNumbers()
{
return new int[] { 2, 4, 6, 8, 10 };
}
我想将数组和显示合并为 1,2,3,4,5,6,7,8,9,10
。
我们如何通过 C# 中的 TAP(基于任务的异步模式)实现这一点? 请大家帮忙提宝贵意见
您当前的实现不需要任何异步代码。
我想这只是一个简化的示例,所以我将它们视为异步方法。
static async Task Main(string[] args)
{
var odds = await GetOddNumbers();
var evens = await GetEvenNumbers();
var numbers = (odds).Zip(evens)
.SelectMany(tuple => new [] { tuple.First, tuple.Second });
Console.ReadLine();
}
- 我们检索两个集合。
- 我们将
odds
中的一个元素组合 (Zip
) 到evens
中的另一个元素。所以,我们最终会得到以下结构(元组数组):
[
(1,2),
(3,4),
(5,6),
(7,8),
(9,10),
]
- 为了将其展平,我们需要调用
SelectMany
。您可以通过First
属性 访问左侧项目,通过Second
属性.
访问右侧项目 3.1) 如果你只调用Select
而不是SelectMany
那么你最终会得到一个数组数组。
[
[1,2],
[3,4],
[5,6],
[7,8],
[9,10],
]
3.2) 但是使用 SelectMany
我们将数组的数组展平为一个简单的数组。
[
1,2,3,4,5,6,7,8,9,10
]
更新:OP 添加了一项新要求(作为注释),即数据应 one-by-one 和异步检索。
为了满足这个我们需要使用IAsyncEnumerable<T>
。这使我们能够在可用时一次提供一个数据。
提供商方
因此,我们必须 return 和 IAsyncEnumerable<int>
而不是 returning Task<int[]>
。 GetOddNumbers
和 GetEvenNumbers
可以这样重写:
public static async IAsyncEnumerable<int> GetOddNumbers()
{
var odds = new int[] { 1, 3, 5, 7, 9 };
foreach (var odd in odds)
{
await Task.Delay(1000); //Whatever async method call
yield return odd;
}
}
public static async IAsyncEnumerable<int> GetEvenNumbers()
{
var evens = new int[] { 2, 4, 6, 8, 10 };
foreach (var even in evens)
{
await Task.Delay(1000); //Whatever async method call
yield return even;
}
}
消费端
我们可以利用 C# 8 新的 await foreach
关键字。IAsyncEnumerable 没有 built-in Zip
函数,所以我们需要使用自定义的,像这样: async-enumerable-dotnet
有了这些,Main
方法将如下所示:
static async Task Main(string[] args)
{
var toBeIterated = async_enumerable_dotnet.AsyncEnumerable.Zip(z => z, GetOddNumbers(), GetEvenNumbers());
await foreach (int[] oddEvenPair in toBeIterated)
{
Console.WriteLine(oddEvenPair[0]);
Console.WriteLine(oddEvenPair[1]);
}
Console.WriteLine("Finished");
Console.ReadLine();
}
它将一次打印出一对数据,然后在下一对之间等待一秒钟。
{1 sec wait}
1
2
{1 sec wait}
3
4
{1 sec wait}
5
6
{1 sec wait}
7
8
{1 sec wait}
9
10
Finished