Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# Zip N IEnumerable<;T>;她在一起吗?同时迭代它们?_C#_.net_Linq - Fatal编程技术网

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());
    }
}