C# Zip N IEnumerable<;T>;她在一起吗?同时迭代它们?
我有:-C# Zip N IEnumerable<;T>;她在一起吗?同时迭代它们?,c#,.net,linq,C#,.net,Linq,我有:- IEnumerable<IEnumerable<T>> items; 编辑:另一个示例(在注释中请求):- 我事先不知道有多少序列,也不知道每个序列中有多少元素。我可能有1000个序列,每个序列中有1000000个元素,并且我可能只需要前10个,所以如果可以的话,我想使用源序列的(惰性)枚举。特别是,如果我能帮助的话,我不想创建一个新的数据结构 是否有一个内置方法(类似于IEnumerable.Zip)可以做到这一点 还有其他方法吗?现在经过轻微测试,并进行有
IEnumerable<IEnumerable<T>> items;
编辑:另一个示例(在注释中请求):-
我事先不知道有多少序列,也不知道每个序列中有多少元素。我可能有1000个序列,每个序列中有1000000个元素,并且我可能只需要前10个,所以如果可以的话,我想使用源序列的(惰性)枚举。特别是,如果我能帮助的话,我不想创建一个新的数据结构
是否有一个内置方法(类似于IEnumerable.Zip)可以做到这一点
还有其他方法吗?现在经过轻微测试,并进行有效处理
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> JaggedPivot<T>(
this IEnumerable<IEnumerable<T>> source)
{
List<IEnumerator<T>> originalEnumerators = source
.Select(x => x.GetEnumerator())
.ToList();
try
{
List<IEnumerator<T>> enumerators = originalEnumerators
.Where(x => x.MoveNext()).ToList();
while (enumerators.Any())
{
List<T> result = enumerators.Select(x => x.Current).ToList();
yield return result;
enumerators = enumerators.Where(x => x.MoveNext()).ToList();
}
}
finally
{
originalEnumerators.ForEach(x => x.Dispose());
}
}
}
public class TestExtensions
{
public void Test1()
{
IEnumerable<IEnumerable<int>> myInts = new List<IEnumerable<int>>()
{
Enumerable.Range(1, 20).ToList(),
Enumerable.Range(21, 5).ToList(),
Enumerable.Range(26, 15).ToList()
};
foreach(IEnumerable<int> x in myInts.JaggedPivot().Take(10))
{
foreach(int i in x)
{
Console.Write("{0} ", i);
}
Console.WriteLine();
}
}
}
公共静态类扩展
{
公共静态可数JaggedPivot(
这是(不可数的来源)
{
列表originalEnumerators=源
.Select(x=>x.GetEnumerator())
.ToList();
尝试
{
列表枚举数=原始枚举数
.Where(x=>x.MoveNext()).ToList();
while(枚举数.Any())
{
列表结果=枚举数。选择(x=>x.Current).ToList();
收益结果;
枚举数=枚举数。其中(x=>x.MoveNext()).ToList();
}
}
最后
{
ForEach(x=>x.Dispose());
}
}
}
公共类测试扩展
{
公共void Test1()
{
IEnumerable myInts=新列表()
{
Enumerable.Range(1,20).ToList(),
Enumerable.Range(21,5).ToList(),
可枚举的.Range(26,15).ToList()
};
foreach(myInts.JaggedPivot()中的IEnumerable x.Take(10))
{
foreach(整数i在x中)
{
Console.Write(“{0}”,i);
}
Console.WriteLine();
}
}
}
如果您能保证结果的使用方式,那么这样做相当简单。但是,如果结果可能以任意顺序使用,则可能需要对所有内容进行缓冲。考虑这一点:
var results = MethodToBeImplemented(sequences);
var iterator = results.GetEnumerator();
iterator.MoveNext();
var first = iterator.Current;
iterator.MoveNext();
var second = iterator.Current;
foreach (var x in second)
{
// Do something
}
foreach (var x in first)
{
// Do something
}
为了获得“second”中的项目,您必须迭代所有子序列,超过第一个项目。如果您希望在first
中迭代项目是有效的,您需要记住项目或准备重新评估子序列
同样,您需要将子序列缓冲为IEnumerable
值,或者每次都重新读取整个批次
基本上,这是一整罐蠕虫,很难以一种适合所有情况的方式优雅地完成:(如果你有一个特定的情况,有适当的限制,我们可以提供更多帮助。这里有一个稍微短一点,但毫无疑问效率较低:
Enumerable.Range(0,items.Select(x => x.Count()).Max())
.Select(x => items.SelectMany(y => y.Skip(x).Take(1)));
这个怎么样
List<string[]> items = new List<string[]>()
{
new string[] { "a", "b", "c" },
new string[] { "1", "2", "3" },
new string[] { "x", "y" },
new string[] { "y", "z", "w" }
};
var x = from i in Enumerable.Range(0, items.Max(a => a.Length))
select from z in items
where z.Length > i
select z[i];
List items=新列表()
{
新字符串[]{“a”、“b”、“c”},
新字符串[]{“1”、“2”、“3”},
新字符串[]{“x”,“y”},
新字符串[]{“y”、“z”、“w”}
};
var x=可枚举范围中的i(0,items.Max(a=>a.Length))
在项目中从z中选择
其中z.长度>i
选择z[i];
您可以像这样组合现有运算符
IEnumerable<IEnumerable<int>> myInts = new List<IEnumerable<int>>()
{
Enumerable.Range(1, 20).ToList(),
Enumerable.Range(21, 5).ToList(),
Enumerable.Range(26, 15).ToList()
};
myInts.SelectMany(item => item.Select((number, index) => Tuple.Create(index, number)))
.GroupBy(item => item.Item1)
.Select(group => group.Select(tuple => tuple.Item2));
IEnumerable myInts=new List()
{
Enumerable.Range(1,20).ToList(),
Enumerable.Range(21,5).ToList(),
可枚举的.Range(26,15).ToList()
};
myInts.SelectMany(item=>item.Select((number,index)=>Tuple.Create(index,number)))
.GroupBy(item=>item.Item1)
.Select(group=>group.Select(tuple=>tuple.Item2));
基于此,此代码的性能应该更好:
public static IEnumerable<IEnumerable<T>> JaggedPivot<T>(
this IEnumerable<IEnumerable<T>> source)
{
var originalEnumerators = source.Select(x => x.GetEnumerator()).ToList();
try
{
var enumerators =
new List<IEnumerator<T>>(originalEnumerators.Where(x => x.MoveNext()));
while (enumerators.Any())
{
yield return enumerators.Select(x => x.Current).ToList();
enumerators.RemoveAll(x => !x.MoveNext());
}
}
finally
{
originalEnumerators.ForEach(x => x.Dispose());
}
}
公共静态IEnumerable JaggedPivot(
这是(不可数的来源)
{
var originalEnumerators=source.Select(x=>x.GetEnumerator()).ToList();
尝试
{
变量枚举数=
新列表(originalEnumerators.Where(x=>x.MoveNext());
while(枚举数.Any())
{
产生返回枚举数。选择(x=>x.Current).ToList();
枚举数.RemoveAll(x=>!x.MoveNext());
}
}
最后
{
ForEach(x=>x.Dispose());
}
}
不同之处在于,枚举数变量并非总是被重新创建。如果项包含三个序列,会发生什么?这类似于(包括N=2的情况)查看Eric Lippert的博客(从一个SO问题的答案扩展而来)关于计算任意多个序列上的笛卡尔积。除了对不同长度的要求外,这听起来很像矩阵的转置。我在这里为LINQ写了一个转置方法:@Richard:添加了一个例子,@James:是的,但是如果你事先知道有多少个序列,这很容易:(,@Anthony:唉,Eric可以使用累加器,因此不需要pivot,@dtb:你的转置方法看起来是一个好的开始。请注意,你没有处理任何迭代器,这可能是不好的,这取决于迭代器所迭代的内容。InnnnInteresting。我不知道当有lazi时,这些迭代器方法最终会被激活这种情况正在发生。尽管如此,这是有道理的,因为调用方最终将调用懒惰的IEnumerator。我接受了这个答案,但请确保您也阅读了Jon Skeet的答案。谢谢!谢天谢地,我可以保证结果将按顺序使用。这是否减轻了在DavidB的答案中调用“ToList”的需要?(现在开始测试)@Iain:我想是的,尽管要正确处理可能很复杂。您仍然需要将子序列引用本身作为
IEnumerable
.Hmmm进行缓冲。与其返回IEnumerable
,不如传入一个要对每个值执行的操作,或者诸如此类的操作?这会让事情变得简单得多!我不知道我可以在一个动作中传递墨迹(好主意,不过我会记住,以后会遇到类似的问题!)。在这个阶段,我想,如果让它变得优雅,会让它变得超级复杂,我就直接把它全部内联起来。如果我的内存中的数据已经以我所使用的形式存在
List<string[]> items = new List<string[]>()
{
new string[] { "a", "b", "c" },
new string[] { "1", "2", "3" },
new string[] { "x", "y" },
new string[] { "y", "z", "w" }
};
var x = from i in Enumerable.Range(0, items.Max(a => a.Length))
select from z in items
where z.Length > i
select z[i];
IEnumerable<IEnumerable<int>> myInts = new List<IEnumerable<int>>()
{
Enumerable.Range(1, 20).ToList(),
Enumerable.Range(21, 5).ToList(),
Enumerable.Range(26, 15).ToList()
};
myInts.SelectMany(item => item.Select((number, index) => Tuple.Create(index, number)))
.GroupBy(item => item.Item1)
.Select(group => group.Select(tuple => tuple.Item2));
public static IEnumerable<IEnumerable<T>> JaggedPivot<T>(
this IEnumerable<IEnumerable<T>> source)
{
var originalEnumerators = source.Select(x => x.GetEnumerator()).ToList();
try
{
var enumerators =
new List<IEnumerator<T>>(originalEnumerators.Where(x => x.MoveNext()));
while (enumerators.Any())
{
yield return enumerators.Select(x => x.Current).ToList();
enumerators.RemoveAll(x => !x.MoveNext());
}
}
finally
{
originalEnumerators.ForEach(x => x.Dispose());
}
}