代码改变世界

一个迭代小算法,根据指定的个数对下标进行分组

2014-03-27 22:45  兜兜里没有药  阅读(286)  评论(0编辑  收藏  举报

很少写博客,一般都在博客园打酱油,希望大家指点指点。

实现效果:

比如:第一行2个,第二行3个,第三行5个,第四行1个, (2,3,4,1)会一直循环分组,直到全部数据分组完成。

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Bulrush.Linq.Wrappers
{
    /// <summary>
    /// 分组包装器
    /// </summary>
    /// <typeparam name="T">要分组的对象的类型</typeparam>
    public sealed class GroupByWrapper<T>
    {
        readonly IEnumerable<T> _dataSource;

        /// <summary>
        /// 构造分组包装器
        /// </summary>
        /// <param name="dataSource">要进行分组的数据源</param>
        public GroupByWrapper(IEnumerable<T> dataSource)
        {
            _dataSource = dataSource;
        }

        /// <summary>
        /// 根据指定每组的个数进行分组
        /// <remarks>
        /// 将循环每组的个数集合进行分组,直到全部数据分组完成
        /// </remarks>
        /// </summary>
        /// <param name="counts">每组的个数集合</param>
        public IEnumerable<IGrouping<int, T>> Get(IEnumerable<int> counts)
        {
            if (counts == null || counts.Count() < 1)
                throw new ArgumentNullException("counts");

            var countEnumerator = counts.GetEnumerator();
            var dataEnumerator = _dataSource.GetEnumerator();
            int curIndex = 0;
            Grouping<int, T> group;

            do
            {
                if (!dataEnumerator.MoveNext())
                    break;

                group = BuildGroup(curIndex, dataEnumerator, countEnumerator);
                yield return group;

                curIndex++;
            } while (true);
        }

        #region 私有方法成员

        private Grouping<int, T> BuildGroup(int index, IEnumerator<T> data, IEnumerator<int> counts)
        {
            var group = new Grouping<int, T>();

            if (!counts.MoveNext())
            {
                counts.Reset();
                counts.MoveNext();
            }

            group.Key = index;
            group.Source = BuildGroupSource(data, counts.Current).ToList();
            return group;
        }

        private IEnumerable<T> BuildGroupSource(IEnumerator<T> data, int count)
        {
            while (count > 0)
            {
                yield return data.Current;
                count--;
                if (count <= 0) //如果当前组已完成,退出
                    break;

                if (!data.MoveNext()) //如果所有数据分组完成,退出
                    break;
            }
        }

        #endregion
    }

    internal class Grouping<TKey, TElement>
        : IGrouping<TKey, TElement>
    {
        public TKey Key { get; set; }

        protected internal IEnumerable<TElement> Source { get; set; } 

        public IEnumerator<TElement> GetEnumerator()
        {
            return Source.GetEnumerator();
        }

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }

 使用迭代yield return的时候需要注意不要中途去获取数据,入.Count(), ToList()等,或则会造成最终获取的数据个别项丢失。

性能差不多1一千万条 130ms

 

写的不好  体谅体谅 (●'◡'●)