C# 压缩C中可枚举的多个/任意数
在Linq中,我们可以使用以下方法将两个列表组合起来: 我希望等效于压缩任意数量的相同类型的枚举。方法签名有点像这样:C# 压缩C中可枚举的多个/任意数,c#,linq,C#,Linq,在Linq中,我们可以使用以下方法将两个列表组合起来: 我希望等效于压缩任意数量的相同类型的枚举。方法签名有点像这样: public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner) IEnumerator<T>[
public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)
IEnumerator<T>[] enumerators = inputs.Select(inp => inp.GetEnumerator()).ToArray();
int len = enumerators.Length;
while (true) {
TResult[] result = new TResult[len];
for(int i = 0; i < len; ++i) {
if (!enumerators[i].MoveNext()) yield break;
result[i] = resultSelector(enumerators[i].Current);
}
yield return result;
}
当作为可枚举项进行迭代时,它返回一个可枚举项,其中包含来自每个相应可枚举项的元素
这在任何地方都存在吗?或者使用现有的Linq方法构建是否简单?聚合多个ZIP?因为输入是一个数组,所以您可以创建一个IEnumerator[] 然后给他们每个人打电话。大概是这样的:
public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)
IEnumerator<T>[] enumerators = inputs.Select(inp => inp.GetEnumerator()).ToArray();
int len = enumerators.Length;
while (true) {
TResult[] result = new TResult[len];
for(int i = 0; i < len; ++i) {
if (!enumerators[i].MoveNext()) yield break;
result[i] = resultSelector(enumerators[i].Current);
}
yield return result;
}
由于输入是数组,因此可以创建IEnumerator[] 然后给他们每个人打电话。大概是这样的:
public static IEnumerable<TResult> Zip<TIn, TResult>(IEnumerable<IEnumerable<TIn>>inputs, Func<IEnumerable<TIn>, TResult> combiner)
IEnumerator<T>[] enumerators = inputs.Select(inp => inp.GetEnumerator()).ToArray();
int len = enumerators.Length;
while (true) {
TResult[] result = new TResult[len];
for(int i = 0; i < len; ++i) {
if (!enumerators[i].MoveNext()) yield break;
result[i] = resultSelector(enumerators[i].Current);
}
yield return result;
}
那么
using System;
using System.Collections.Generic;
using System.Linq;
...
public static IEnumerable<TResult> Zip<T, TResult>(
this IEnumerable<T> source,
Func<IList<T>, TResult> resultSelector,
params IEnumerable<T>[] others)
{
if (resultSelector == null)
{
throw new ArgumentNullException("resultSelector");
}
var enumerators = new List<IEnumerator<T>>(others.Length + 1);
enumerators.Add(source.GetEnumerator());
enumerators.AddRange(others.Select(e => e.GetEnumerator()));
try
{
var buffer = new T[enumerators.Count];
while (true)
{
for (var i = 0; i < enumerators.Count; i++)
{
if (!enumerators[i].MoveNext())
{
yield break;
}
buffer[i] = enumerators[i].Current;
}
yield return resultSelector(buffer);
}
}
finally
{
foreach (var enumerator in enumerators)
{
enumerator.Dispose();
}
}
}
那么
using System;
using System.Collections.Generic;
using System.Linq;
...
public static IEnumerable<TResult> Zip<T, TResult>(
this IEnumerable<T> source,
Func<IList<T>, TResult> resultSelector,
params IEnumerable<T>[] others)
{
if (resultSelector == null)
{
throw new ArgumentNullException("resultSelector");
}
var enumerators = new List<IEnumerator<T>>(others.Length + 1);
enumerators.Add(source.GetEnumerator());
enumerators.AddRange(others.Select(e => e.GetEnumerator()));
try
{
var buffer = new T[enumerators.Count];
while (true)
{
for (var i = 0; i < enumerators.Count; i++)
{
if (!enumerators[i].MoveNext())
{
yield break;
}
buffer[i] = enumerators[i].Current;
}
yield return resultSelector(buffer);
}
}
finally
{
foreach (var enumerator in enumerators)
{
enumerator.Dispose();
}
}
}
应该是相当简单的建设。可以在上找到双元素Zip的参考实现;推广到n个元素应该不难。我已经在自己身上实现了,如果我没有得到任何答案,我会把它作为一个答案发布,但是,我很想知道它是否已经存在,或者是否有比我更好的实现。据我所知,框架中没有任何东西,我很惊讶没有找到一个实现,“不使用谷歌,也不使用谷歌。”海因茨:是的,我已经做了大量的搜索应该是相当简单的建设。可以在上找到双元素Zip的参考实现;推广到n个元素应该不难。我已经在自己身上实现了,如果我没有得到任何答案,我会把它作为一个答案发布,但是,我很想知道它是否已经存在,或者是否有比我更好的实现。据我所知,框架中没有任何东西,我很惊讶没有找到一个实现,“不使用谷歌,也不使用谷歌。”海因茨:是的,我已经做了大量的搜索啊,是的,我不应该在那个签名中发布数组,但是你已经给出了一个与我已经得到的非常相似的答案,参数Func对我来说有点奇怪。我想说的是Func combinerI,我想用Zip组合一对列表的方式来组合所有列表。Zip中的结果选择器有两个参数。经过检查,我的答案与您的答案非常相似,但有些不同。希望这意味着我们在正确的直线上+1。啊,是的,我不应该在那个签名中发布数组,但是你得到了一个与我已经得到的非常相似的答案。参数Func对我来说有点奇怪。我想说的是Func combinerI,我想用Zip组合一对列表的方式来组合所有列表。Zip中的结果选择器有两个参数。经过检查,我的答案与您的答案非常相似,但有些不同。希望这意味着我们的思路是正确的+1。IEnumerator是IDisposable的,但这段代码从不调用Dispose@ta.speot.is已修复。IEnumerator可IDisposable,但此代码从不调用Dispose@ta.speot.是固定的。