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

什么';在两个列表中应用运算符的C#惯用方法是什么?,c#,list,C#,List,我习惯于这样做(从其他语言): 这将获取两个大小相同的列表,并对其成员应用一个函数,一次一个,以获得结果列表。它可以是一个简单的乘法函数(如上所述)或更复杂的函数: c = b>a ? b-a : 0; // c = 4, 0, 0 我可以想出几种不同的方法在C语言中实现这一点,但我不确定一个受过C语言培训的程序员会如何做到这一点。在C#world,正确的做法是什么 (我唯一要问的是c=f(a,b)的位置。我熟悉创建列表和访问它们的元素。) 对于编辑后更复杂的问题: var c =

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

这将获取两个大小相同的列表,并对其成员应用一个函数,一次一个,以获得结果列表。它可以是一个简单的乘法函数(如上所述)或更复杂的函数:

 c = b>a ? b-a : 0;  // c = 4, 0, 0
我可以想出几种不同的方法在C语言中实现这一点,但我不确定一个受过C语言培训的程序员会如何做到这一点。在C#world,正确的做法是什么

(我唯一要问的是c=f(a,b)的位置。我熟悉创建列表和访问它们的元素。)

对于编辑后更复杂的问题:

var c = a.Zip(b, (x, y) => x > y ? x - y : 0);
请注意,
Zip
是一种扩展方法,同时也是一种from扩展方法,因此,如果lambda是给定查询提供程序可以处理的,则可以将其作为数据库上的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);
    }
}
公共类MyExtraLinqyStuff
{
公共静态IEnumerable Zip(此IEnumerable第一,IEnumerable第二,Func resultSelector)
{
//立即执行空检查;
if(first==null)
抛出新的ArgumentNullException(“第一”);
if(秒==null)
抛出新的异常(“第二个”);
if(resultSelector==null)
抛出新ArgumentNullException(“结果选择器”);
返回DoZip(第一个、第二个、结果选择器);
}
私有静态IEnumerable DoZip(此IEnumerable第一,IEnumerable第二,Func resultSelector)
{
使用(var enF=first.GetEnumerator())
使用(var enS=second.GetEnumerator())
while(enF.MoveNext()&&enS.MoveNext())
生成返回结果选择器(enF.Current,enS.Current);
}
}

对于.NET2.0或.NET3.0,您可以使用相同的方法,但不能将其作为扩展方法,它可以回答评论中的另一个问题;当时在.NET中并没有一种真正惯用的方式来做这样的事情,或者至少在我们使用.NET编写代码的人中并没有达成一致意见。我们中的一些人在工具包中有上述方法(虽然显然不是扩展方法),但这更多的是因为我们受到了其他语言和库的影响,而不是其他任何东西(例如,我之所以做上述事情,是因为我从C++的STL中知道了一些东西,但这并不是唯一可能的灵感来源)

如果您没有使用.NET 4.0,下面介绍如何编写自己的扩展方法来进行压缩

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);
        }
    }
}
static IEnumerable Zip(此IEnumerable第一,IEnumerable第二,Func resultSelector)
{
使用(IEnumerator e1=first.GetEnumerator())
使用(IEnumerator e2=second.GetEnumerator())
{
而(e1.MoveNext()&&e2.MoveNext())
{
产生返回结果选择器(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]));
}
List list1=newlist(){4,7,9};
List list2=新列表(){11,2,3};
List newList=新列表();
对于(int i=0;i

当然,这是假设列表大小相同且不变。如果您提前知道列表大小,您也可以将其实例化为正确的大小,然后在循环过程中设置元素。

假设.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);
var a=newlist(){1,2,3};
var b=新列表(){5,1,2};
变量c=a.Select((x,i)=>b[i]*x);
结果:

五,

二,

六,


好问题,由于需要并行索引,我可能会使用
for
循环来实现这一点。对于与简单标量相乘,使用
Select
语句。查看LINQ的内部和外部是否有类似的操作,因为它为选择或将运算符应用于列表提供了简洁的通知@作为一个答案,请给出一个使用LINQ的例子,我会很高兴地投票。也请考虑。@ Mikelkj-OrrRin,链接已经死了,但是请看。重要的是,Net 4的新的,所以如果你瞄准3.5,它将不可用。(但将自己实现为一个扩展方法并不难)记不起它是
Zip
+1@DavidG或者
Enumerable.Range(1,5)。选择(x=>x*x)
@Joe不太可能,但是快速查看一下,添加到您自己的项目中并不难。根据您最近关于无法在.NET 2.0或3.0中执行扩展方法的更新,我不久前发现您可以在.NET 2.0或3.0中添加对扩展方法的支持。但是,您需要使用Visual Studio 2008或更高版本才能工作。现在,我们已经涵盖了所有基础,包括3.5版本后的解决方案、3.5版本后的解决方案和3.5版本前的解决方案。(对于大小问题,可以通过使for循环
for(int i=0;i
@ScottChamberlain您的解决方案中有哪些功能在3.5之前不可用?@BenAaronson扩展方法。但是您可以通过一个@ScottChamberlain扩展方法将扩展方法支持放回。@ScottChamberlain扩展方法是的,但是您使用什么LINQ功能?@ErikPhilips good.NET代码并不认为它被正确调用,如果它是为了重用的话(仅在有限的情况下调用私有方法是另一回事。)
Select
Linq函数吗?是程序集
System.Core
中的扩展方法。
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]));
}
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);