代码之家  ›  专栏  ›  技术社区  ›  Kev Hunter

如何将IEnumerable<String>拆分为IEnumerable<String>[duplicate]组

  •  29
  • Kev Hunter  · 技术社区  · 15 年前

    我有一个 IEnumerable<string &燃气轮机;我想分成三组,如果我的输入有6项,我会得到一个 IEnumerable<IEnumerable<string>> 返回两个项目,每个项目将包含一个 IEnumerable<string>

    我正在寻找如何使用Linq而不是简单的for循环来实现这一点

    8 回复  |  直到 15 年前
        1
  •  33
  •   Matthew Watson    3 年前

    这是对此线程的延迟回复,但这里有一个不使用任何临时存储的方法:

    public static class EnumerableExt
    {
        public static IEnumerable<IEnumerable<T>> Partition<T>(this IEnumerable<T> input, int blockSize)
        {
            var enumerator = input.GetEnumerator();
    
            while (enumerator.MoveNext())
            {
                yield return nextPartition(enumerator, blockSize);
            }
        }
    
        private static IEnumerable<T> nextPartition<T>(IEnumerator<T> enumerator, int blockSize)
        {
            do
            {
                yield return enumerator.Current;
            }
            while (--blockSize > 0 && enumerator.MoveNext());
        }
    }
    

    class Program
    {
        static void Main(string[] args)
        {
            var someNumbers = Enumerable.Range(0, 10000);
    
            foreach (var block in someNumbers.Partition(100))
            {
                Console.WriteLine("\nStart of block.");
    
                foreach (int number in block)
                {
                    Console.Write(number);
                    Console.Write(" ");
                }
            }
    
            Console.WriteLine("\nDone.");
            Console.ReadLine();
        }
    }
    

    但是,请注意以下关于该方法局限性的评论:

    1. 如果你改变主意 foreach foreach (var block in someNumbers.Partition(100).ToArray())

        2
  •  32
  •   Mehrdad Afshari    15 年前
    var result = sequence.Select((s, i) => new { Value = s, Index = i })
                         .GroupBy(item => item.Index / 3, item => item.Value);
    

    请注意,这将返回一个 IEnumerable<IGrouping<int,string>> 在功能上与您想要的类似。但是,如果您严格地需要将其键入为 IEnumerable<IEnumerable<string>> Enumerable.Cast :

    var result = sequence.Select((s, i) => new { Value = s, Index = i })
                         .GroupBy(item => item.Index / 3, item => item.Value)
                         .Cast<IEnumerable<string>>();
    
        3
  •  22
  •   brunosp86 diceguyd30    13 年前

    我知道这已经得到了回答,但如果您计划经常获取IEnumerables的切片,那么我建议您使用如下通用扩展方法:

    public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> source, int chunkSize)
    {
        return source.Where((x,i) => i % chunkSize == 0).Select((x,i) => source.Skip(i * chunkSize).Take(chunkSize));
    }
    

    sequence.Split(3)

    (如果您不喜欢已经为字符串定义了“split”,可以将其命名为“slice”或“chunk”。“split”正是我碰巧称之为我的。)

        4
  •  16
  •   Arne Claassen    13 年前

    public static IEnumerable<IEnumerable<T>> Split2<T>(this IEnumerable<T> source, int chunkSize) {
        var chunk = new List<T>(chunkSize);
        foreach(var x in source) {
            chunk.Add(x);
            if(chunk.Count <= chunkSize) {
                continue;
            }
            yield return chunk;
            chunk = new List<T>(chunkSize);
        }
        if(chunk.Any()) {
            yield return chunk;
        }
    }
    

    这样我就可以按需构建每个块。我希望我能避免这种情况 List<T>

        5
  •  2
  •   Martijn Pieters    12 年前

    使用Microsoft.Responsive,您可以非常简单地执行此操作,并且只需在源代码中迭代一次。

    IEnumerable<string> source = new List<string>{"1", "2", "3", "4", "5", "6"};
    
    IEnumerable<IEnumerable<string>> splited = source.ToObservable().Buffer(3).ToEnumerable();
    
        6
  •  2
  •   Colonel Panic    12 年前

    我们可以改进@Afshari的解决方案来进行真正的惰性评估。我们使用 GroupAdjacentBy

    sequence
    .Select((x, i) => new { Value = x, Index = i })
    .GroupAdjacentBy(x=>x.Index/3)
    .Select(g=>g.Select(x=>x.Value))
    

    因为这些群是一个接一个地产生的,所以这种解决方案对长序列或无限序列有效。

        7
  •  1
  •   Ronnie Overby    12 年前

    using System.Collections.Generic;
    using System.Linq;
    
    public static class EnumerableExtensions
    {
        public static IEnumerable<IEnumerable<T>> GroupsOf<T>(this IEnumerable<T> enumerable, int size)
        {
            return enumerable.Select((v, i) => new {v, i}).GroupBy(x => x.i/size, x => x.v);
        }
    }
    
        8
  •  0
  •   Alex Essilfie    13 年前

    while 迭代器可以,但结果会像普通LINQ一样缓存在内存中,直到需要时为止。
    这是密码。

    public IEnumerable<IEnumerable<T>> Paginate<T>(this IEnumerable<T> source, int pageSize)
    {
        List<IEnumerable<T>> pages = new List<IEnumerable<T>>();
        int skipCount = 0;
    
        while (skipCount * pageSize < source.Count) {
            pages.Add(source.Skip(skipCount * pageSize).Take(pageSize));
            skipCount += 1;
        }
    
        return pages;
    }