【问题标题】:Merge 2 arrays with Odd and Even numbers and display as Natural Numbers with TASK Operation合并 2 个具有奇数和偶数的数组,并通过 TASK 操作显示为自然数
【发布时间】:2020-09-21 11:12:10
【问题描述】:

假设我们有 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(基于任务的异步模式)来实现这一点? 请帮忙提出宝贵的建议。

【问题讨论】:

  • 为什么要使用 TAP 进行这个简单的操作?什么是异步的?
  • 欢迎来到 StackOverflow。为什么这些方法是异步的?它们同步返回值。如果它只是一个简化的例子,那么你应该尝试使用Zip,就像这样:var numbers = (await GetOddNumbers()).Zip(await GetEvenNumbers());
  • 对不起,我错过了展平它。您应该在 linq 表达式的末尾添加:.SelectMany((f) =&gt; new int[] {f.First, f.Second})

标签: c# task-parallel-library c#-8.0


【解决方案1】:

您当前的实现不需要任何异步代码。

我想这只是一个简化的例子,所以我将它们视为异步方法。

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();
}
  1. 我们检索这两个集合。
  2. 我们将odds 中的一个元素组合(Zip) 到evens 中的另一个元素。因此,我们最终会得到以下结构(元组数组):
[
  (1,2),
  (3,4),
  (5,6),
  (7,8),
  (9,10),
]
  1. 为了展平它,我们需要调用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 添加了一个新要求(作为注释),即应逐个异步检索数据。

为了满足这一点,我们需要使用IAsyncEnumerable&lt;T&gt;。这使我们能够在数据可用时一次提供一个数据。

提供方

因此,我们必须返回IAsyncEnumerable&lt;int&gt;,而不是返回Task&lt;int[]&gt;GetOddNumbersGetEvenNumbers 可以这样重写:

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 没有内置的 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 个任务,例如,检索 Task1 的第一个值,然后是 Task2 的第一个值,然后是 task1 的第二个值,然后是 task2 的第二个值等等。我希望应该有一些可能性使用 TAP 实现此目的。问题只是一个示例数据。但在实时,这些值将被异步检索。
  • @vinothkarunanithy 是的,我绝对得到你想要的。我会在几分钟内根据这些新要求更新我的答案。
  • @vinothkarunanithy 我已经更新了我的答案,请检查一下。
猜你喜欢
  • 1970-01-01
  • 2020-01-03
  • 2021-01-15
  • 1970-01-01
  • 2016-07-14
  • 2021-12-11
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多