ArraySegment - 返回实际的段 C# [英] ArraySegment - Returning the actual segment C#

查看:23
本文介绍了ArraySegment - 返回实际的段 C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找返回基本由 ArraySegment 在偏移量和计数方面持有的段的方法.尽管 ArraySegment 保存了完整的原始数组,但它只是用对段的任何更改都反映到原始数组中这一事实来分隔它.问题或者说 ArraySegment 的限制是它不会将段本身作为一个整体返回,我必须遍历这些值.返回整个细分市场的最佳方式是什么?

I have been looking around on ways to return the segment which is basically held by ArraySegment in terms of offset and count. Although ArraySegment holds the complete and original array, it just delimits it with the fact that any changes to the segment are reflected into the original. The problem or say the limitation with ArraySegment is that it will not return the segment itself as a whole and I have to traverse the values. What would be the best way to return the segment as a whole?

 byte[] input = new byte[5]{1,2,3,4,5};
 ArraySegment<byte> delimited = new ArraySegment<byte>(input,0,2);
 byte[] segment = HERE I NEED SOMETHING THAT WILL RETURN THE SEGMENT i.e. [0,1,2]

最重要的一点,segment 不能是副本,而应该是指原始数组.如果对segment进行了任何更改,它们必须反映在原始数组中.

The most important point, segment must not be a copy but should refer to the original array. If any changes to segment are done, they must be reflected in the original array.

非常感谢任何提示,谢谢!

Any tips are highly appreciated, thanks!

分配基准:经过 ThomasdigEmAll

好的,我对来自 digEmAll 和 Thomas 的代码进行了一些基准测试,令我惊讶的是,代码速度要快得多.正是我拼命寻找的东西.这是结果.

Ok, I ran some benchmarks against the code from digEmAll and Thomas, and to my surprise the code is overwhelmingly faster. Just what I was desperately looking for. Here are the results.

Construct             Size    Elements assigned    Iterations       Time
_______________________________________________________________________________

ArraySegmentWrapper   1500        1500              1000000       396.3 ms
Array.Copy            1500        1500              1000000       4389.04 ms

正如您所看到的巨大差异,我很清楚我将使用 ArraySegment 的代码.下面是基准测试代码.请注意,这可能有点有偏见,因为人们会争论为什么新"被放入一个循环中.我只是想在不移动大部分代码的情况下尽可能地重现我目前手头的情况.这让我很开心!

As you can see the whopping difference, it is very clear to me that I shall be using the code for ArraySegment. Below is the benchmarking code. Please note that this might be a bit biased as people would argue why "new" has been put inside a loop. I am just trying to reproduce the situation I currently have at hand at resolve it as much as possible without moving much of the code. This just made my day!

namespace ArraySegmentWrapped
{
    class Program
    {

        public static Stopwatch stopWatch = new Stopwatch();
        public static TimeSpan span = new TimeSpan();
        public static double totalTime = 0.0;
        public static int iterations = 1000000;

        static void Main(string[] args)
        {
            int size = 1500;
            int startIndex = 0;
            int endIndex = 1499;
            byte[] array1 = new byte[size];
            byte[] array2 = null;

            for (int index = startIndex; index < size; index++)
            {
                array1[index] = (byte)index;
            }

            ArraySegmentWrapper<byte> arraySeg;

            for (int index = 0; index < iterations; index++)
            {
                stopWatch.Start();
                arraySeg = new ArraySegmentWrapper<byte>(array1, startIndex, endIndex);            
                stopWatch.Stop();
                totalTime += stopWatch.Elapsed.TotalMilliseconds;
            }

            Console.WriteLine("ArraySegment:{0:F6}", totalTime / iterations);
            stopWatch.Reset();
            totalTime = 0.0;

            for (int index = 0; index < iterations; index++)
            {
                stopWatch.Start();
                array2 = new byte[endIndex - startIndex + 1];
                Array.Copy(array1, startIndex, array2, 0, endIndex);
                stopWatch.Stop();
                totalTime += stopWatch.Elapsed.TotalMilliseconds;
            }
            Console.WriteLine("Array.Copy:{0:F6}", totalTime / iterations);                        


        }
    }
// Code for ArraySegmentWrapper goes here    

}

访问基准(更新)因此,在 Thomas 指出基准并表示与 ArraySegment 相比访问简单数组会更快之后,他是完全正确的.但是 digEmAll 指出我应该在发布模式下测试(抱歉在调试模式下测试的旧错误),我留下的代码几乎与上面相同(迭代减少两个零 - 不能等待很长时间才能输出来,抱歉)和一些修改以访问相同数量的元素,以下是我得到的.

ACCESS BENCHMARKS (Updated) So after what Thomas had pointed about the benchmarks and said that access to simple arrays would be faster as compared to ArraySegment, he was totally right. But with digEmAll pointing out that I should test in Release mode (sorry for the old mistake of testing in debug mode), I left the code almost the same as above(iterations reduced by two zeros - could not wait very long for the output to come, sorry) and some modifications to access the same number of elements, Below is what I got.

Construct             Size    Elements accessed    Iterations       Time
_______________________________________________________________________________

ArraySegmentWrapper   1500        1500              1000000       5268.3 ms
Array.Copy            1500        1500              1000000       4812.4 ms

得出的结论是,虽然赋值非常快,但通过 ArraySegments 访问却很慢.

Concluded that although assingment is very fast, access is slow via ArraySegments.

推荐答案

Thomas Levesque 的建议 我已经构建了一个简单的 ArraySegmentWrapper 类以这样使用:

Starting from Thomas Levesque's suggestion I've built a simple ArraySegmentWrapper<T> class to use in this way:

static void Main(string[] args)
{
    int[] arr = new int[10];
    for (int i = 0; i < arr.Length; i++)
        arr[i] = i;

    // arr = 0,1,2,3,4,5,6,7,8,9

    var segment = new ArraySegmentWrapper<int>(arr, 2, 7);
    segment[0] = -1;
    segment[6] = -1;
    // now arr = 0,1,-1,3,4,5,6,7,-1,9


    // this prints: -1,3,4,5,6,7,-1
    foreach (var el in segment)
        Console.WriteLine(el);
}

实施:

public class ArraySegmentWrapper<T> : IList<T>
{
    private readonly ArraySegment<T> segment;

    public ArraySegmentWrapper(ArraySegment<T> segment)
    {
        this.segment = segment;
    }

    public ArraySegmentWrapper(T[] array, int offset, int count)
        : this(new ArraySegment<T>(array, offset, count))
    {
    }

    public int IndexOf(T item)
    {
        for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
            if (Equals(segment.Array[i], item))
                return i;
        return -1;
    }

    public void Insert(int index, T item)
    {
        throw new NotSupportedException();
    }

    public void RemoveAt(int index)
    {
        throw new NotSupportedException();
    }

    public T this[int index]
    {
        get
        {
            if (index >= this.Count)
                throw new IndexOutOfRangeException();
            return this.segment.Array[index + this.segment.Offset];
        }
        set
        {
            if (index >= this.Count)
                throw new IndexOutOfRangeException();
            this.segment.Array[index + this.segment.Offset] = value;
        }
    }

    public void Add(T item)
    {
        throw new NotSupportedException();
    }

    public void Clear()
    {
        throw new NotSupportedException();
    }

    public bool Contains(T item)
    {
        return this.IndexOf(item) != -1;
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
        {
            array[arrayIndex] = segment.Array[i];
            arrayIndex++;
        }
    }

    public int Count
    {
        get { return this.segment.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        throw new NotSupportedException();
    }

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = segment.Offset; i < segment.Offset + segment.Count; i++)
            yield return segment.Array[i];
    }

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

<小时>

正如@JeppeStigNielsen 在评论中指出的那样,由于 .NET 4.5 ArraySegment 实现了 IList

这篇关于ArraySegment - 返回实际的段 C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆