在两个列表中应用运算符的C#方法是什么?

我习惯于这样做(来自其他语言):

a = 1, 2, 3; b = 5, 1, 2; c = a * b; // c = 5, 2, 6 

这需要两个相同大小的列表,并将一个函数应用于其成员,一次一个地获得结果列表。 它可能是一个像乘法(上面)那样简单的函数或更复杂的函数:

  c = b>a ? ba : 0; // c = 4, 0, 0 

我可以想到在C#中用几种不同的方法来做到这一点,但我不确定一个C#训练的程序员会怎么做。 在C#世界中进行这种操作的正确方法是什么?

(我所问的唯一部分是 c = f(a,b) 。我熟悉创build列表和访问元素。)

 var c = a.Zip(b, (x, y) => x * y); 

对于编辑之后的更复杂的一个:

 var c = a.Zip(b, (x, y) => x > y ? x - y : 0); 

请注意, ZipEnumerable一个扩展方法,它作用于IEnumerable<T>Queryable ,作用于IQueryable<T> ,因此,作为数据库上的SQL查询处理,或者在.NET中内存之外的其他方式处理。

有人提到,在评论中4.0是新的。 自己实现3.5并不难:

 public class MyExtraLinqyStuff { public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector) { //Do null checks immediately; if(first == null) throw new ArgumentNullException("first"); if(second == null) throw new ArgumentNullException("second"); if(resultSelector == null) throw new ArgumentNullException("resultSelector"); return DoZip(first, second, resultSelector); } private static IEnumerable<TResult> DoZip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector) { using(var enF = first.GetEnumerator()) using(var enS = second.GetEnumerator()) while(enF.MoveNext() && enS.MoveNext()) yield return resultSelector(enF.Current, enS.Current); } } 

对于.NET2.0或.NET3.0,您可以使用相同的扩展方法,但不能从注释中回答另一个问题。 当时在.NET中并没有真正的做这种事情的习惯性方式,或者至less在我们这些用.NET编码的时候没有达成一致的共识。 我们中的一些人在我们的工具包中有类似上面的方法(尽pipe显然不是扩展方法),但是更多的是我们受到其他语言和库的影响,而不是其他任何东西(比如我正在做类似上面的事情, C ++的STL,但这不是唯一可能的灵感来源)

假设.net 3.5与等长列表:

 var a = new List<int>() { 1, 2, 3 }; var b = new List<int>() { 5, 1, 2 }; var c = a.Select((x, i) => b[i] * x); 

结果:

2

6

DotNetFiddle.Net示例

如果你不使用.NET 4.0,这里是如何编写你自己的扩展方法做一个Zip。

 static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> resultSelector) { using (IEnumerator<TFirst> e1 = first.GetEnumerator()) using (IEnumerator<TSecond> e2 = second.GetEnumerator()) { while (e1.MoveNext() && e2.MoveNext()) { yield return resultSelector(e1.Current, e2.Current); } } } 

对于没有LINQ的.NET版本,我会推荐一个for循环来完成这个工作:

 List<int> list1 = new List<int>(){4,7,9}; List<int> list2 = new List<int>(){11,2,3}; List<int> newList = new List<int>(); for (int i = 0; i < list1.Count; ++i) { newList.Add(Math.Max(list1[i], list2[i])); } 

当然,这个列表是相同的大小,并没有改变。 如果你事先知道列表的大小,你也可以将它实例化为正确的大小,然后在循环中设置元素。