【问题标题】:c# 2 for each loop if one works the other doesn'tc# 2 for each loop 如果一个工作另一个不工作
【发布时间】:2021-07-11 17:14:51
【问题描述】:

我有 2 个不同的正则表达式匹配,目前使用 2 个 foreach 循环来获取匹配值。 但是,就目前而言,如果一个 foreach 有效,那么另一个无效。

试试 1

foreach (string dir in multiTrimmed1)
{
  foreach (string dir2 in multiTrimmed2)
  {
    var forVal2= dir.Replace("$", "").Replace(" ", "");
    var forVal3 = dir2.Replace(",", "");
    var parsedParams= new ParsedMethod()
    {
      Value1= forVal1,
      Value2 = Convert.ToDecimal(forVal2),
      Value3 = Convert.ToDecimal(forVal3),
      Value4 = forVal4
    };
    MergeAllValues(parsedParams);
   }
}

所以这里的问题是 multiTrimmed1 和 multiTrimmed2 每个都有 string[4]。

假设 A、B、C 和 D。 在我的尝试 1 中,我希望 forVal2 和 forVal3 正确地通过循环。

我的意思是,当 forVal2 为 A 时,forVal3 也是 A - 将其发送到 MergeAllValues、next、B 和 B - 将其发送到 MergeAllValues、next、C 和 C - 将其发送到 MergeAllValues 和下一个 D 和D - 将其发送到 MergeAllValues。

目前只有一个循环有效。如果 forVal3 的值更改为 A、B、C 和 D - 那么 forVal2 将在 A 处停止。

试试 2

bool loopAgain = true;
while (loopAgain)
{
  loopAgain = false;
  foreach (string dir in multiTrimmed1)
   {
    foreach (string dir2 in multiTrimmed2)
    {
      var forVal2= dir.Replace("$", "").Replace(" ", "");
      var forVal3 = dir2.Replace(",", "");
      var parsedParams= new ParsedMethod()
      {
        Value1= forVal1,
        Value2 = Convert.ToDecimal(forVal2),
        Value3 = Convert.ToDecimal(forVal3),
        Value4 = forVal4
      };
      MergeAllValues(parsedParams);
      loopAgain = true;
      break;
   }
}

在这种情况下,forVal2 得到的值很好,但 forVal3 保持在 A

试试 3

bool loopAgain = true;
while (loopAgain)
{
  loopAgain = false;
  foreach (string dir in multiTrimmed1)
   {
    var forVal2= dir.Replace("$", "").Replace(" ", "");
    
    foreach (string dir2 in multiTrimmed2)
    {
      var forVal3 = dir2.Replace(",", "");
      var parsedParams= new ParsedMethod()
      {
        Value1= forVal1,
        Value2 = Convert.ToDecimal(forVal2),
        Value3 = Convert.ToDecimal(forVal3),
        Value4 = forVal4
      };
      MergeAllValues(parsedParams);
      loopAgain = true;
      break;
   }
}

仍然只有工作循环有效。我怎样才能使两者都工作?

【问题讨论】:

  • 您在寻找Zip,而不是寻找multiTrimmed1multiTrimmed2 的所有组合(如尝试1)?
  • 我没用过。如果这是解决方案,我会研究它
  • "在这种情况下,forVal2 得到的值很好,但 forVal3 保持在 A" - break; 退出包含它的循环。您在 Try 2 和 Try 3 中无条件地调用它,因此在 multiTrimmed2 的第一次迭代中,它将退出循环。这实际上与编写 string dir2 = multiTrimmed2.First(); 并完全取消最内层循环相同。
  • 如果能确认multiTrimmed1和multiTrimmed2有1:1的关系,由每个元素在列表中的位置决定(即multiTrimmed1中的位置0对应multiTrimmed2中的位置0,1对1,2对2等)然后我可以用Zip写一个答案。
  • 那么一个for循环呢?您遍历所有索引,然后您可以使用这些索引从两个列表中访问相应的项目

标签: c#


【解决方案1】:

您已经断言 multiTrimmed1multiTrimmed2 具有基于元素位置的 1:1 关系,因此我们可以使用 .Zip

foreach (var (dir, dir2) in multiTrimmed1.Zip(multiTrimmed2, (a,b) => (a, b)))
{
      string forVal2 = dir.Replace("$", "").Replace(" ", "");
      string forVal3 = dir2.Replace(",", "");
      var parsedParams = new ParsedMethod()
      {
        Value1 = forVal1,
        Value2 = Convert.ToDecimal(forVal2),
        Value3 = Convert.ToDecimal(forVal3),
        Value4 = forVal4
      };
      MergeAllValues(parsedParams);
}

Try it online

基本上我们在这里所做的是同时循环遍历multiTrimmed1multiTrimmed2 以在每个位置生成一个ValueTuple 元素(a 来自multiTrimmed1 和@ 987654334@ 来自multiTrimmed2)。然后我们使用var (dir, dir2) 分解它,以便我们可以单独访问这些值。

您在上面的代码中遇到问题的原因是,对于具体的集合,例如 List<T> 或数组 (T[]),foreach 每次都会从头开始。

所以当你写这样的东西时:

foreach (var a in colA)
{
    foreach (var b in colB)
    {

    }
}

您是说“对于 colA 中的每个项目,运行以下代码”(它本身恰好也包含一个循环。所以您不是同时循环两个集合,而是循环通过外部集合(@987654341 @) 并且对于 colA 中的每个项目,您还将遍历 colB 中的每个项目。

Zip 的方法是从colA 获取一个项目并从colB 获取一个项目,执行合并功能,然后产生值。然后它从colA 获取下一项,从colB 获取下一项并生成它们。这使您可以有效地同时遍历两个集合。

因此,为了阐明它在内部的作用,您可以使用以下近似值实现自己的 Zip 方法:

public static IEnumerable<T> MyZip<T, A, B>(IEnumerable<A> eA, IEnumerable<B> eB, Func<A, B, T> mergeFunc)
{
    var aEnumerator = eA.GetEnumerator(); // get an enumerator for eA
    var bEnumerator = eB.GetEnumerator(); // get an enumerator for eB

    // while there are more items to be read in a AND b
    while (aEnumerator.MoveNext() && bEnumerator.MoveNext())
    {
        // execute the mergeFunction on the value from a and the value from b and store the result
        T itemResult = mergeFunc(aEnumerator.Current, bEnumerator.Current);
        // return the result to the caller
        yield return itemResult;
    }
}

Try it online

【讨论】:

  • Zip 还可以循环 3、4、5 ……更多的收藏吗?只是好奇.. 通过做 (a, b, c, d ...) ? (如果都是 1:1 关系)
  • @davis 不能。 this question 介绍了如何使用 Zip 执行此操作。本质上是你Zip,然后你又是Zip。或者,您可以扩展我的演示 Zip 方法来处理两个以上的集合。
猜你喜欢
  • 2020-03-18
  • 2021-04-29
  • 2018-08-29
  • 1970-01-01
  • 1970-01-01
  • 2012-06-13
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
相关资源
最近更新 更多