Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.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# 有人能想出一个更好的枚举器版本吗?_C#_Ienumerable_Enumerator - Fatal编程技术网

C# 有人能想出一个更好的枚举器版本吗?

C# 有人能想出一个更好的枚举器版本吗?,c#,ienumerable,enumerator,C#,Ienumerable,Enumerator,我对下面的方法很满意。它接受一个可枚举的、已排序的、不相交的范围列表,并跳过不在范围内的项。如果范围为空,我们只需遍历每个项目。可枚举范围和范围列表都可能很大。我们希望此方法具有尽可能高的性能 有人能想出一个更优雅的代码吗?我主要对C#实现感兴趣,但如果有人有三个字符的APL实现,那也很酷 public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Pair<int,

我对下面的方法很满意。它接受一个可枚举的、已排序的、不相交的范围列表,并跳过不在范围内的项。如果范围为空,我们只需遍历每个项目。可枚举范围和范围列表都可能很大。我们希望此方法具有尽可能高的性能

有人能想出一个更优雅的代码吗?我主要对C#实现感兴趣,但如果有人有三个字符的APL实现,那也很酷

public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Pair<int, int>> ranges) 
{
    Debug.Assert(ranges == null || ranges.Count > 0);

    int currentItem = 0;
    Pair<int, int> currentRange = new Pair<int, int>();
    int currentRangeIndex = -1;
    bool betweenRanges = false;
    if (ranges != null) 
    {
        currentRange = ranges[0];
        currentRangeIndex = 0;
        betweenRanges = currentRange.First > 0;
    }

    foreach (T item in source) 
    {
        if (ranges != null) {
            if (betweenRanges) {
                if (currentItem == currentRange.First)
                    betweenRanges = false;
                else {
                    currentItem++;
                    continue;
                }
            }
        }

        yield return item;

        if (ranges != null) {
            if (currentItem == currentRange.Second) {
                if (currentRangeIndex == ranges.Count - 1)
                    break; // We just visited the last item in the ranges

                currentRangeIndex = currentRangeIndex + 1;
                currentRange = ranges[currentRangeIndex];
                betweenRanges = true;
            }
        }

        currentItem++;
    }
}
公共静态IEnumerable范围(IEnumerable源、列表范围)
{
Assert(ranges==null | | ranges.Count>0);
int currentItem=0;
对currentRange=新对();
int currentRangeIndex=-1;
bool-betweenRanges=false;
如果(范围!=null)
{
currentRange=范围[0];
currentRangeIndex=0;
betweenRanges=currentRange.First>0;
}
foreach(源中的T项)
{
如果(范围!=null){
如果(介于范围之间){
if(currentItem==currentRange.First)
betweenRanges=假;
否则{
currentItem++;
持续
}
}
}
收益回报项目;
如果(范围!=null){
if(currentItem==currentRange.Second){
if(currentRangeIndex==ranges.Count-1)
break;//我们刚刚访问了范围中的最后一项
currentRangeIndex=currentRangeIndex+1;
currentRange=范围[currentRangeIndex];
betweenRanges=真;
}
}
currentItem++;
}
}

可能在
源代码上使用linq,例如:

public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Pair<int, int>> ranges)
{
    if(ranges == null)
        return null;
    return source.Where((item, index) => ranges.Any(y => y.First < index && y.Second > index)).AsEnumerable();
}
公共静态IEnumerable范围(IEnumerable源、列表范围)
{
如果(范围==null)
返回null;
返回source.Where((item,index)=>ranges.Any(y=>y.Firstindex)).AsEnumerable();
}
我面前没有我的Windows PC,我不确定我是否正确理解了你的代码,但我尝试理解了你的文本,上面的代码可以工作。。。。或者类似的


更新:关于性能问题,我建议您使用一些简单的测试和计时功能来测试性能。

可能会在
源代码上使用linq,例如:

public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Pair<int, int>> ranges)
{
    if(ranges == null)
        return null;
    return source.Where((item, index) => ranges.Any(y => y.First < index && y.Second > index)).AsEnumerable();
}
公共静态IEnumerable范围(IEnumerable源、列表范围)
{
如果(范围==null)
返回null;
返回source.Where((item,index)=>ranges.Any(y=>y.Firstindex)).AsEnumerable();
}
我面前没有我的Windows PC,我不确定我是否正确理解了你的代码,但我尝试理解了你的文本,上面的代码可以工作。。。。或者类似的


更新:关于性能问题,我建议您使用一些简单的测试和计时功能来测试性能。

您可以将源列表复制到一个数组,然后针对每个范围,您可以阻止从新源数组复制到适当位置的目标数组。如果可以将源集合作为数组传入,那么这将是一种更好的方法。如果必须进行初始复制,则该操作的值为O(N)加上O(M),其中M是最终数组中的项目总数。因此,无论哪种情况,结果都是O(N)。

您可以将源列表复制到一个数组,然后针对每个范围,您可以阻止从新源数组复制到正确位置的目标数组。如果可以将源集合作为数组传入,那么这将是一种更好的方法。如果必须进行初始复制,则该操作的值为O(N)加上O(M),其中M是最终数组中的项目总数。因此,无论哪种情况,结果都是O(N)。

我的看法是这样的。我发现它更容易理解,如果不是更优雅的话

public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Tuple<int, int>> ranges)
{
    if (ranges == null)
        return source;

    Debug.Assert(ranges.Count > 0);
    return WalkRangesInternal(source, ranges);
}

static IEnumerable<T> WalkRangesInternal<T>(IEnumerable<T> source, List<Tuple<int, int>> ranges)
{
    int currentItem = 0;
    var rangeEnum = ranges.GetEnumerator();
    bool moreData = rangeEnum.MoveNext();

    using (var sourceEnum = source.GetEnumerator())
        while (moreData)
        {
            // skip over every item in the gap between ranges
            while (currentItem < rangeEnum.Current.Item1
               && (moreData = sourceEnum.MoveNext()))
                currentItem++;
            // yield all the elements in the range
            while (currentItem <= rangeEnum.Current.Item2
               && (moreData = sourceEnum.MoveNext()))
            {
                yield return sourceEnum.Current;
                currentItem++;
            }
            // advance to the next range
            moreData = rangeEnum.MoveNext();
        }
}
公共静态IEnumerable范围(IEnumerable源、列表范围)
{
如果(范围==null)
返回源;
断言(ranges.Count>0);
返回WalkRange内部(源、范围);
}
静态IEnumerable WalkRange内部(IEnumerable源、列表范围)
{
int currentItem=0;
var rangeEnum=ranges.GetEnumerator();
bool moreData=rangeEnum.MoveNext();
使用(var sourceEnum=source.GetEnumerator())
while(更多数据)
{
//跳过范围间隔中的每个项目
而(currentItemwhile(currentItem这是我的看法。我发现它更容易理解,如果不是更优雅的话

public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Tuple<int, int>> ranges)
{
    if (ranges == null)
        return source;

    Debug.Assert(ranges.Count > 0);
    return WalkRangesInternal(source, ranges);
}

static IEnumerable<T> WalkRangesInternal<T>(IEnumerable<T> source, List<Tuple<int, int>> ranges)
{
    int currentItem = 0;
    var rangeEnum = ranges.GetEnumerator();
    bool moreData = rangeEnum.MoveNext();

    using (var sourceEnum = source.GetEnumerator())
        while (moreData)
        {
            // skip over every item in the gap between ranges
            while (currentItem < rangeEnum.Current.Item1
               && (moreData = sourceEnum.MoveNext()))
                currentItem++;
            // yield all the elements in the range
            while (currentItem <= rangeEnum.Current.Item2
               && (moreData = sourceEnum.MoveNext()))
            {
                yield return sourceEnum.Current;
                currentItem++;
            }
            // advance to the next range
            moreData = rangeEnum.MoveNext();
        }
}
公共静态IEnumerable范围(IEnumerable源、列表范围)
{
如果(范围==null)
返回源;
断言(ranges.Count>0);
返回WalkRange内部(源、范围);
}
静态IEnumerable WalkRange内部(IEnumerable源、列表范围)
{
int currentItem=0;
var rangeEnum=ranges.GetEnumerator();
bool moreData=rangeEnum.MoveNext();
使用(var sourceEnum=source.GetEnumerator())
while(更多数据)
{
//跳过范围间隔中的每个项目
而(currentItem
public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source,
                                           List<Pair<int, int>> ranges)
{
    if (source == null)
        throw new ArgumentNullException("source");

    // If ranges is null, just return the source. From spec.
    return ranges == null ? source : RangeIterate(source, ranges);
}

private static IEnumerable<T> RangeIterate<T>(IEnumerable<T> source, 
                                              List<Pair<int, int>> ranges)
{
    // The key bit: a lazy sequence of all valid indices belonging to
    // each range. No buffering.
    var validIndices = from range in ranges
                       let start = Math.Max(0, range.First)
                       from validIndex in Enumerable.Range(start, range.Second - start + 1)
                       select validIndex;

    int currentIndex = -1;

    using (var indexErator = validIndices.GetEnumerator())
    {
        // Optimization: Get out early if there are no ranges.
        if (!indexErator.MoveNext())
            yield break;

        foreach (var item in source)
        {
            if (++currentIndex == indexErator.Current)
            {
               // Valid index, yield.
                yield return item;

                // Move to the next valid index.
                // Optimization: get out early if there aren't any more.
                if (!indexErator.MoveNext())
                    yield break;
            }
        }
    }
}
公共静态IEnumerable范围(IEnumerable源、,
列表范围)
{
我
public static IEnumerable<T> WalkRanges<T>(IEnumerable<T> source, List<Pair<int, int>> ranges)
{
    int currentIndex = 0;
    int currentRangeIndex = 0;
    int maxRangeIndex = ranges.Length;
    bool done = false;
    foreach(var item in source)
    {
        if(currentIndex > range[currentRangeIndex].Second)
        {
           while(currentIndex > range[currentRangeIndex].Second)
           {
               if(!++currentRangeIndex < maxRangeIndex)
               {
                   // We've passed last range => 
                   // set done = true to break outer loop and then break
                   done = true;
                   break;
               }
           }
           if(currentIndex > range[currentRangeIndex].First)
               yield item; // include if larger than first since we now it's smaller than second
        }
        else if(currentIndex > range[currentRangeIndex].First)
        {
            // If higher than first and lower than second we're in range
            yield item;
        }
        if(done) // if done break outer loop
            break;

        currentIndex++; // always increase index when advancint through source
    }
}