1

我有三个长度相同的数组,我想使用 .Zip 可选性从中提取最大值/最小值(或应用任何其他函数Fct),谁能帮我以一种干净的方式做到这一点?

double [] x = new  double []  {1,3,5,6,6};
double [] y = new  double [] {5,6,8,3,4} ;
double [] z = new  double  [] {9,4,10,0,8} ;
double []  result = z.Zip(x.Zip(y, (a, b) => Math.Max(a, b)).ToList(), (c, maxab) => Math.Max(c, maxab)).ToArray();

{double[5]}
[0]: 9.0
[1]: 6.0
[2]: 10.0
[3]: 6.0
[4]: 8.0

我的问题是:有没有办法做一个Fct (a,b,c)而不是做两次:Fct (a,b) then Fct ( Fct (a,b),c)当 Fct 不一定可以拆分时那感觉。

4

2 回答 2

1

改进的答案(为了语法上的乐趣):

static IEnumerable<T> Map<T>(Func<IEnumerable<T>, T> f, 
                             params IEnumerable<T>[] arr)
{
  var enums = Array.ConvertAll(arr, x => x.GetEnumerator());
  try
  {
    while (enums.All(x => x.MoveNext()))
    {
      yield return f(enums.Select(x => x.Current));
    }
  }
  finally
  {
    foreach (var e in enums) e.Dispose();
  }
}

static void Main(string[] args)
{
  double[] w = { 1, 2, 3, 4, 5 };
  double[] x = { 1, 3, 5, 6, 6 };
  double[] y = { 5, 6, 8, 3, 4 };
  double[] z = { 9, 4, 10, 0, 8 };

  var r = Map(Enumerable.Max, w, x, y, z).ToArray();

  ...
}

玩得开心 :)

于 2012-11-16T11:01:19.400 回答
0

以下函数是 Zip 函数的测试版本,它运行三个集合,它不会一次计算所有结果,而是像 Linq 的 Zip 函数一样使用延迟执行。

static class ThreeWayZip
{
  public static IEnumerable<TResult> Zip3<TFirst, TSecond, TThird, TResult>(
      this IEnumerable<TFirst> first,
      IEnumerable<TSecond> second,
      IEnumerable<TThird> third,
      Func<TFirst, TSecond, TThird, TResult> resultSelector)
  {
    if(first == null || second == null || third == null) 
    { throw new ArgumentNullException(); }

    using (var iterator1 = first.GetEnumerator())
    using (var iterator2 = second.GetEnumerator())
    using (var iterator3 = third.GetEnumerator())
    {
      while(iterator1.MoveNext() 
        && iterator2.MoveNext()
        && iterator3.MoveNext())
      {
        yield return resultSelector(
          iterator1.Current, iterator2.Current, iterator3.Current);
      }

    }
  }
}

以下是我运行的测试:

int Min3(int x, int y, int z) 
{
      if(x<=y)
      {
        if(x<=z)
        { //x<=z && x<=y
          return x;
        }
        //z<x && x<=y 
        return z;
      }
      //y<x
      if(z<=y) return z;
      //y<z && y<x
      return y;
}

[TestMethod]
public void Test_Zip3()
{
  int[] a = { 2, 3, 5 };
  int[] b = { 3, 2, 5 };
  int[] c = { 5, 1, 5 };

  IEnumerable<int> result = a.Zip3(b, c, Min3);
  CollectionAssert.AreEqual(new[] {2, 1, 5}, result.ToArray());
}

[TestMethod]
public void Zip_With_Different_ArrayLength()
{
  int[] a = { 2, 3, };
  int[] b = { 3, 2, 5 };
  int[] c = { 5, 1, 5, 8 };

  var result = a.Zip3(b, c, Min3);
  CollectionAssert.AreEqual(new[] {2, 1}, result.ToArray());
}

[TestMethod]
public void Zip_With_EmptyArray()
{
  int[] a = { 2, 3, };
  int[] b = { 3, 2, 5 };
  int[] c = { };

  var result = a.Zip3(b, c, Min3);
  CollectionAssert.AreEqual(new int[0], result.ToArray());
}

[TestMethod]
public void Zip_With_First_ArrayEmpty()
{
  int[] a = { };
  int[] b = { 3, 2, 5 };
  int[] c = { 1, 8, };

  var result = a.Zip3(b, c, Min3);
  CollectionAssert.AreEqual(new int[0], result.ToArray());
}


[TestMethod]
public void Zip_With_All_Arrays_Empty()
{
  int[] a = { };
  int[] b = { };
  int[] c = { };

  var result = a.Zip3(b, c, Min3);
  CollectionAssert.AreEqual(new int[0], result.ToArray());
}
于 2012-11-16T11:54:27.407 回答