How do I clone a range of array elements to a new array?

前端 未结 25 1014
北海茫月
北海茫月 2020-11-22 16:07

I have an array X of 10 elements. I would like to create a new array containing all the elements from X that begin at index 3 and ends in index 7. Sure I can easily write a

相关标签:
25条回答
  • 2020-11-22 16:30

    I see you want to do Cloning, not just copying references. In this case you can use .Select to project array members to their clones. For example, if your elements implemented IClonable you could do something like this:

    var newArray = array.Skip(3).Take(5).Select(eachElement => eachElement.Clone()).ToArray();
    

    Note: This solution requires .NET Framework 3.5.

    0 讨论(0)
  • 2020-11-22 16:33

    This is the optimal way, I found, to do this:

    private void GetSubArrayThroughArraySegment() {
      int[] array = { 10, 20, 30 };
      ArraySegment<int> segment = new ArraySegment<int>(array,  1, 2);
      Console.WriteLine("-- Array --");
      int[] original = segment.Array;
      foreach (int value in original)
      {
        Console.WriteLine(value);
      }
      Console.WriteLine("-- Offset --");
      Console.WriteLine(segment.Offset);
      Console.WriteLine("-- Count --");
      Console.WriteLine(segment.Count);
    
      Console.WriteLine("-- Range --");
      for (int i = segment.Offset; i <= segment.Count; i++)
      {
        Console.WriteLine(segment.Array[i]);
      }
    }
    

    Hope It Helps!

    0 讨论(0)
  • 2020-11-22 16:37

    You can use Array.Copy(...) to copy into the new array after you've created it, but I don't think there's a method which creates the new array and copies a range of elements.

    If you're using .NET 3.5 you could use LINQ:

    var newArray = array.Skip(3).Take(5).ToArray();
    

    but that will be somewhat less efficient.

    See this answer to a similar question for options for more specific situations.

    0 讨论(0)
  • 2020-11-22 16:37

    use extention method :

    public static T[] Slice<T>(this T[] source, int start, int end)
        {
            // Handles negative ends.
            if (end < 0)
            {
                end = source.Length + end;
            }
            int len = end - start;
    
            // Return new array.
            T[] res = new T[len];
            for (int i = 0; i < len; i++)
            {
                res[i] = source[i + start];
            }
            return res;
        }
    

    and you can use it

    var NewArray = OldArray.Slice(3,7);
    
    0 讨论(0)
  • 2020-11-22 16:38

    You could add it as an extension method:

    public static T[] SubArray<T>(this T[] data, int index, int length)
    {
        T[] result = new T[length];
        Array.Copy(data, index, result, 0, length);
        return result;
    }
    static void Main()
    {
        int[] data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        int[] sub = data.SubArray(3, 4); // contains {3,4,5,6}
    }
    

    Update re cloning (which wasn't obvious in the original question). If you really want a deep clone; something like:

    public static T[] SubArrayDeepClone<T>(this T[] data, int index, int length)
    {
        T[] arrCopy = new T[length];
        Array.Copy(data, index, arrCopy, 0, length);
        using (MemoryStream ms = new MemoryStream())
        {
            var bf = new BinaryFormatter();
            bf.Serialize(ms, arrCopy);
            ms.Position = 0;
            return (T[])bf.Deserialize(ms);
        }
    }
    

    This does require the objects to be serializable ([Serializable] or ISerializable), though. You could easily substitute for any other serializer as appropriate - XmlSerializer, DataContractSerializer, protobuf-net, etc.

    Note that deep clone is tricky without serialization; in particular, ICloneable is hard to trust in most cases.

    0 讨论(0)
  • 2020-11-22 16:39

    You can take class made by Microsoft:

    internal class Set<TElement>
    {
        private int[] _buckets;
        private Slot[] _slots;
        private int _count;
        private int _freeList;
        private readonly IEqualityComparer<TElement> _comparer;
    
        public Set()
            : this(null)
        {
        }
    
        public Set(IEqualityComparer<TElement> comparer)
        {
            if (comparer == null)
                comparer = EqualityComparer<TElement>.Default;
            _comparer = comparer;
            _buckets = new int[7];
            _slots = new Slot[7];
            _freeList = -1;
        }
    
        public bool Add(TElement value)
        {
            return !Find(value, true);
        }
    
        public bool Contains(TElement value)
        {
            return Find(value, false);
        }
    
        public bool Remove(TElement value)
        {
            var hashCode = InternalGetHashCode(value);
            var index1 = hashCode % _buckets.Length;
            var index2 = -1;
            for (var index3 = _buckets[index1] - 1; index3 >= 0; index3 = _slots[index3].Next)
            {
                if (_slots[index3].HashCode == hashCode && _comparer.Equals(_slots[index3].Value, value))
                {
                    if (index2 < 0)
                        _buckets[index1] = _slots[index3].Next + 1;
                    else
                        _slots[index2].Next = _slots[index3].Next;
                    _slots[index3].HashCode = -1;
                    _slots[index3].Value = default(TElement);
                    _slots[index3].Next = _freeList;
                    _freeList = index3;
                    return true;
                }
                index2 = index3;
            }
            return false;
        }
    
        private bool Find(TElement value, bool add)
        {
            var hashCode = InternalGetHashCode(value);
            for (var index = _buckets[hashCode % _buckets.Length] - 1; index >= 0; index = _slots[index].Next)
            {
                if (_slots[index].HashCode == hashCode && _comparer.Equals(_slots[index].Value, value))
                    return true;
            }
            if (add)
            {
                int index1;
                if (_freeList >= 0)
                {
                    index1 = _freeList;
                    _freeList = _slots[index1].Next;
                }
                else
                {
                    if (_count == _slots.Length)
                        Resize();
                    index1 = _count;
                    ++_count;
                }
                int index2 = hashCode % _buckets.Length;
                _slots[index1].HashCode = hashCode;
                _slots[index1].Value = value;
                _slots[index1].Next = _buckets[index2] - 1;
                _buckets[index2] = index1 + 1;
            }
            return false;
        }
    
        private void Resize()
        {
            var length = checked(_count * 2 + 1);
            var numArray = new int[length];
            var slotArray = new Slot[length];
            Array.Copy(_slots, 0, slotArray, 0, _count);
            for (var index1 = 0; index1 < _count; ++index1)
            {
                int index2 = slotArray[index1].HashCode % length;
                slotArray[index1].Next = numArray[index2] - 1;
                numArray[index2] = index1 + 1;
            }
            _buckets = numArray;
            _slots = slotArray;
        }
    
        internal int InternalGetHashCode(TElement value)
        {
            if (value != null)
                return _comparer.GetHashCode(value) & int.MaxValue;
            return 0;
        }
    
        internal struct Slot
        {
            internal int HashCode;
            internal TElement Value;
            internal int Next;
        }
    }
    

    and then

    public static T[] GetSub<T>(this T[] first, T[] second)
        {
            var items = IntersectIteratorWithIndex(first, second);
            if (!items.Any()) return new T[] { };
    
    
            var index = items.First().Item2;
            var length = first.Count() - index;
            var subArray = new T[length];
            Array.Copy(first, index, subArray, 0, length);
            return subArray;
        }
    
        private static IEnumerable<Tuple<T, Int32>> IntersectIteratorWithIndex<T>(IEnumerable<T> first, IEnumerable<T> second)
        {
            var firstList = first.ToList();
            var set = new Set<T>();
            foreach (var i in second)
                set.Add(i);
            foreach (var i in firstList)
            {
                if (set.Remove(i))
                    yield return new Tuple<T, Int32>(i, firstList.IndexOf(i));
            }
        }
    
    0 讨论(0)
提交回复
热议问题