다양한 어레이 요소를 새 어레이로 복제하려면 어떻게 해야 합니까?
저는 10개의 요소로 구성된 X 배열을 가지고 있습니다.인덱스 3에서 시작하여 인덱스 7에서 끝나는 X의 모든 요소를 포함하는 새 배열을 만들고 싶습니다.물론 루프를 쉽게 작성할 수 있지만 코드를 최대한 깨끗하게 유지하고 싶습니다.C#에서 나를 위해 그것을 할 수 있는 방법이 있습니까?
(의사 코드)와 같은 것:
Array NewArray = oldArray.createNewArrayFromRange(int BeginIndex , int EndIndex)
Array.Copy 제 요구에 맞지 않습니다.새 배열의 항목을 복제해야 합니다. Array.copy C-Style C-Style입니다.memcpy동등하게, 그것은 제가 찾고 있는 것이 아닙니다.
확장 방법으로 추가할 수 있습니다.
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}
}
복제 업데이트(원래 질문에서는 명확하지 않음).딥 클론을 원하는 경우 다음과 같은 작업을 참조하십시오.
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);
}
}
이를 위해서는 객체를 직렬화해야 합니다([Serializable]또는ISerializable.), 하만지하.필요에 따라 다른 시리얼라이저를 쉽게 대체할 수 있습니다.XmlSerializer,DataContractSerializer등 »
딥 클론은 직렬화 없이는 까다롭다는 점에 유의하십시오.ICloneable대부분의 경우 신뢰하기 어렵습니다.
새 배열을 만든 후 를 사용하여 새 배열로 복사할 수 있지만, 새 배열을 만들고 다양한 요소를 복사하는 방법은 없다고 생각합니다.
를 사용하는 경우.LINQ를 사용할 수 있는 NET 3.5:
var newArray = array.Skip(3).Take(5).ToArray();
하지만 그렇게 하면 효율성이 다소 떨어집니다.
보다 구체적인 상황에 대한 옵션은 유사한 질문에 대한 이 답변을 참조하십시오.
사용을 고려해 보셨습니까?ArraySegment?
http://msdn.microsoft.com/en-us/library/1hsbd92d.aspx
참조를 복사하는 것이 아니라 복제를 수행하려는 것이군요.에는 이경사수있다니습할용을 할 수 있습니다..Select어레이 구성원을 클론에 투영합니다.들어 가 예들어요구현경우된가소를ed▁your▁implement▁if를 구현한 경우입니다.IClonable당신은 다음과 같은 것을 할 수 있습니다.
var newArray = array.Skip(3).Take(5).Select(eachElement => eachElement.Clone()).ToArray();
참고: 이 솔루션에는 을 사용해야 합니다.NET Framework 3.5.
다음 코드는 한 줄로 수행합니다.
// Source array
string[] Source = new string[] { "A", "B", "C", "D" };
// Extracting a slice into another array
string[] Slice = new List<string>(Source).GetRange(2, 2).ToArray();
C# 8을 소개했습니다.Range그리고.Index다음과 같이 사용할 수 있는 유형:
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Index i1 = 3; // number 3 from beginning
Index i2 = ^4; // number 4 from end
var slice = a[i1..i2]; // { 3, 4, 5 }
참조:
- https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-core-3-0#ranges-and-indices
- https://devblogs.microsoft.com/dotnet/building-c-8-0/
string[] arr = { "Parrot" , "Snake" ,"Rabbit" , "Dog" , "cat" };
arr = arr.ToList().GetRange(0, arr.Length -1).ToArray();
Marc의 답변을 기반으로 하지만 원하는 복제 동작 추가
public static T[] CloneSubArray<T>(this T[] data, int index, int length)
where T : ICloneable
{
T[] result = new T[length];
for (int i = 0; i < length; i++)
{
var original = data[index + i];
if (original != null)
result[i] = (T)original.Clone();
return result;
}
ICloneable을 구현하는 것이 너무 힘든 작업과 같다면 Hovard Stranden의 Copyable 라이브러리를 사용하여 필요한 많은 작업을 수행할 수 있습니다.
using OX.Copyable;
public static T[] DeepCopySubArray<T>(
this T[] data, int index, int length)
{
T[] result = new T[length];
for (int i = 0; i < length; i++)
{
var original = data[index + i];
if (original != null)
result[i] = (T)original.Copy();
return result;
}
OX에 유의하십시오.복사 가능한 구현은 다음 중 하나와 함께 작동합니다.
그러나 자동 복사가 작동하려면 예를 들어 다음 명령 중 하나가 유지되어야 합니다.
- 해당 형식에는 매개 변수가 없는 생성자가 있어야 합니다.
- 복사 가능한 파일이어야 합니다.
- 해당 유형에 대해 등록된 IInstanceProvider가 있어야 합니다.
그래서 이것은 당신이 가지고 있는 거의 모든 상황을 다루어야 합니다.하위 그래프에 db 연결이나 파일/스트림 핸들과 같은 항목이 포함된 개체를 복제하는 경우 일반화된 모든 딥 복사에 문제가 있는 것은 분명합니다.
만약 당신이 다른 딥 카피 접근법을 사용하기를 원한다면, 이 기사는 다른 몇몇 접근법을 나열하기 때문에 나는 당신 자신의 것을 쓰려고 하지 않는 것을 제안합니다.
이 작업은 상당히 쉽게 수행할 수 있습니다.
object[] foo = new object[10];
object[] bar = new object[7];
Array.Copy(foo, 3, bar, 0, 7);
당신이 찾고 있는 코드는 다음과 같습니다.
Array.Copy(oldArray, 0, newArray, BeginIndex, EndIndex - BeginIndex)
데이터를 복사하는 대신 원래 배열의 일부를 복사하는 것처럼 액세스할 수 있는 래퍼를 만들 수 있습니다.장점은 메모리에 데이터 복사본이 하나도 없다는 것이고, 단점은 데이터에 액세스할 때 약간의 오버헤드가 있다는 것입니다.
public class SubArray<T> : IEnumerable<T> {
private T[] _original;
private int _start;
public SubArray(T[] original, int start, int len) {
_original = original;
_start = start;
Length = len;
}
public T this[int index] {
get {
if (index < 0 || index >= Length) throw new IndexOutOfRangeException();
return _original[_start + index];
}
}
public int Length { get; private set; }
public IEnumerator<T> GetEnumerator() {
for (int i = 0; i < Length; i++) {
yield return _original[_start + i];
}
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
}
용도:
int[] original = { 1, 2, 3, 4, 5 };
SubArray<int> copy = new SubArray<int>(original, 2, 2);
Console.WriteLine(copy.Length); // shows: 2
Console.WriteLine(copy[0]); // shows: 3
foreach (int i in copy) Console.WriteLine(i); // shows 3 and 4
C# 8.0에서는 이제 Python과 같은 역색인 및 범위를 포함하여 다음과 같은 많은 고급 작업을 수행할 수 있습니다.
int[] list = {1, 2, 3, 4, 5, 6};
var list2 = list[2..5].Clone() as int[]; // 3, 4, 5
var list3 = list[..5].Clone() as int[]; // 1, 2, 3, 4, 5
var list4 = list[^4..^0].Clone() as int[]; // reverse index
Array.ConstraintedCopy가 작동합니다.
public static void ConstrainedCopy (
Array sourceArray,
int sourceIndex,
Array destinationArray,
int destinationIndex,
int length
)
복제 요구 사항을 충족하지는 못하지만 다음과 같은 작업을 수행하는 것이 일반적인 방법보다 간단합니다.
Array NewArray = new ArraySegment(oldArray,BeginIndex , int Count).ToArray();
당신이 원하는 것을 할 수 있는 단 하나의 방법은 없습니다.배열의 클래스에 대해 복제 메서드를 사용할 수 있도록 만들어야 합니다.LINQ가 옵션인 경우:
Foo[] newArray = oldArray.Skip(3).Take(5).Select(item => item.Clone()).ToArray();
class Foo
{
public Foo Clone()
{
return (Foo)MemberwiseClone();
}
}
int[] ArrayOne = new int[8] {1,2,3,4,5,6,7,8};
int[] ArrayTwo = new int[5];
Array.ConstrainedCopy(ArrayOne, 3, ArrayTwo, 0, 7-3);
아래는 저의 원래 글입니다.작동하지 않을 것입니다.
int[] ArrayOne = new int[8] {1,2,3,4,5,6,7,8};
int[] ArrayTwo = new int[5];
ArrayOne.CopyTo(ArrayTwo,3); //starts copy at index=3 until it reaches end of
//either array
이거 어때:
public T[] CloneCopy(T[] array, int startIndex, int endIndex) where T : ICloneable
{
T[] retArray = new T[endIndex - startIndex];
for (int i = startIndex; i < endIndex; i++)
{
array[i - startIndex] = array[i].Clone();
}
return retArray;
}
그런 다음 이 기능을 사용해야 하는 모든 클래스에 ICloneable 인터페이스를 구현해야 합니다.
얼마나 깊은지는 잘 모르겠지만,
MyArray.ToList<TSource>().GetRange(beginningIndex, endIndex).ToArray()
그것은 약간 간접비이지만 불필요한 방법을 없앨 수도 있습니다.
복제에 관한 한, 저는 직렬화가 당신의 생성자를 부른다고 생각하지 않습니다.만약 당신이 영화관에서 흥미로운 일을 하고 있다면 이것은 수업의 불변성을 깨뜨릴 수 있습니다.
복제 생성자를 호출하는 가상 복제 방법이 더 안전한 것 같습니다.
protected MyDerivedClass(MyDerivedClass myClass)
{
...
}
public override MyBaseClass Clone()
{
return new MyDerivedClass(this);
}
배열에서 요소를 복제하는 것은 보편적인 방법으로 수행될 수 없습니다.전체 구성원의 심층 복제 또는 단순 복사본을 원하십니까?
ICloneable 인터페이스 또는 이진 직렬화를 사용하여 개체를 복제하는 "최선의 노력" 방식을 사용해 보겠습니다.
public static class ArrayExtensions
{
public static T[] SubArray<T>(this T[] array, int index, int length)
{
T[] result = new T[length];
for (int i=index;i<length+index && i<array.Length;i++)
{
if (array[i] is ICloneable)
result[i-index] = (T) ((ICloneable)array[i]).Clone();
else
result[i-index] = (T) CloneObject(array[i]);
}
return result;
}
private static object CloneObject(object obj)
{
BinaryFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream())
{
formatter.Serialize(stream, obj);
stream.Seek(0,SeekOrigin.Begin);
return formatter.Deserialize(stream);
}
}
}
이것은 완벽한 해결책이 아닙니다. 왜냐하면 어떤 종류의 물체에도 효과가 없기 때문입니다.
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;
}
}
그리고 나서.
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));
}
}
이것이 제가 발견한 최적의 방법입니다.
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]);
}
}
도움이 되길 바래요!
확장 메서드 사용:
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;
}
그리고 당신은 그것을 사용할 수 있습니다.
var NewArray = OldArray.Slice(3,7);
시스템의 코드입니다.사적인.CoreLib.dll:
public static T[] GetSubArray<T>(T[] array, Range range)
{
if (array == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
}
(int Offset, int Length) offsetAndLength = range.GetOffsetAndLength(array.Length);
int item = offsetAndLength.Offset;
int item2 = offsetAndLength.Length;
if (default(T) != null || typeof(T[]) == array.GetType())
{
if (item2 == 0)
{
return Array.Empty<T>();
}
T[] array2 = new T[item2];
Buffer.Memmove(ref Unsafe.As<byte, T>(ref array2.GetRawSzArrayData()), ref Unsafe.Add(ref Unsafe.As<byte, T>(ref array.GetRawSzArrayData()), item), (uint)item2);
return array2;
}
T[] array3 = (T[])Array.CreateInstance(array.GetType().GetElementType(), item2);
Array.Copy(array, item, array3, 0, item2);
return array3;
}
array1 = [5,6,7,8];
int[] array2 = new int[2];
Array.ConstrainedCopy(array1, 1, array2, 0, 2);
array2 = [6,7];
Array.ConstraintedCopy는 5개의 매개 변수를 사용합니다.
sourcearray(sourceArray)
원본 배열의 시작 인덱스(sourceIndex)
대상 배열(destinationArray)
대상 배열의 시작 인덱스(대상)색인)
복사할 요소 수(길이)
public static T[] SubArray<T>(T[] data, int index, int length)
{
List<T> retVal = new List<T>();
if (data == null || data.Length == 0)
return retVal.ToArray();
bool startRead = false;
int count = 0;
for (int i = 0; i < data.Length; i++)
{
if (i == index && !startRead)
startRead = true;
if (startRead)
{
retVal.Add(data[i]);
count++;
if (count == length)
break;
}
}
return retVal.ToArray();
}
언급URL : https://stackoverflow.com/questions/943635/how-do-i-clone-a-range-of-array-elements-to-a-new-array
'codememo' 카테고리의 다른 글
| 를 사용하여 Windows에서 팝업 "토스터" 알림을 만듭니다.그물 (0) | 2023.05.13 |
|---|---|
| 이벤트에서 모든 이벤트 핸들러를 제거하는 방법 (0) | 2023.05.13 |
| Git에서 파일 이름의 대문자화를 어떻게 변경합니까? (0) | 2023.05.13 |
| WPF의 명령을 컨트롤의 더블 클릭 이벤트 핸들러에 바인딩하는 방법은 무엇입니까? (0) | 2023.05.13 |
| SQL Server에서 제약 조건의 이름을 바꾸시겠습니까? (0) | 2023.05.13 |