bestsource

C#의 배열 조각

bestsource 2023. 6. 13. 22:27
반응형

C#의 배열 조각

어떻게 하는 거지?지정된 바이트 배열:

byte[] foo = new byte[4096];

어레이의 첫 번째 x바이트를 별도의 어레이로 가져오려면 어떻게 해야 합니까?(구체적으로, 저는 그것이 필요합니다.IEnumerable<byte>)

이 작업은 다음 작업을 위한 것입니다.Socket가장 쉬운 방법은 Perls 구문과 유사한 배열 슬라이싱입니다.

@bar = @foo[0..40];

그러면 처음 41개의 요소들이 다음으로 되돌아갑니다.@bar배열입니다. C#에 제가 빠진 것이 있나요, 아니면 제가 해야 할 다른 것이 있나요?

LINQ는 도움이 된다면 저(.NET 3.5)의 옵션입니다.

당신은 할 수 있습니다.어레이를 복사하지 않기 때문에 매우 가볍습니다.

string[] a = { "one", "two", "three", "four", "five" };
var segment = new ArraySegment<string>( a, 1, 2 );

배열은 열거할 수 있으므로,foo이미.IEnumerable<byte>그 자체로원하는 것을 얻기 위해 LINQ 시퀀스 방법을 사용하기만 하면 됩니다( 잊지 말고 다음을 포함하십시오).Linq네임스페이스 사용using System.Linq;):

byte[] foo = new byte[4096];

var bar = foo.Take(41);

만약 당신이 정말로 어떤 것으로부터 배열이 필요하다면.IEnumerable<byte>가치, 당신은 사용할 수 있습니다.ToArray()그것을 위한 방법.여기서는 그렇지 않은 것 같습니다.

어레이를 사용할 수 있습니다.CopyTo()방법.

또는 LINQ와 함께 사용할 수 있습니다.Skip()그리고...

byte[] arr = {1, 2, 3, 4, 5, 6, 7, 8};
var subset = arr.Skip(2).Take(2);

C# 8.0/부터 시작.넷코어 3.0

새로운 유형과 함께 어레이 슬라이싱이 지원됩니다.Index그리고.Range추가 중입니다.

범위 구조 문서
구조 문서 색인

Index i1 = 3;  // number 3 from beginning
Index i2 = ^4; // number 4 from end
int[] a = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
Console.WriteLine($"{a[i1]}, {a[i2]}"); // "3, 6"

var slice = a[i1..i2]; // { 3, 4, 5 }

위의 코드 샘플은 C# 8.0 블로그에서 가져온 것입니다.

에 주목하여^prefix는 배열의 에서 세는 것을 나타냅니다.문서 예제에 표시된 대로

var words = new string[]
{
                // index from start    index from end
    "The",      // 0                   ^9
    "quick",    // 1                   ^8
    "brown",    // 2                   ^7
    "fox",      // 3                   ^6
    "jumped",   // 4                   ^5
    "over",     // 5                   ^4
    "the",      // 6                   ^3
    "lazy",     // 7                   ^2
    "dog"       // 8                   ^1
};              // 9 (or words.Length) ^0

Range그리고.Index예를 들어 루프와 같은 슬라이싱 어레이 외부에서도 작동합니다.

Range range = 1..4; 
foreach (var name in names[range])

항목 1 ~ 4를 반복합니다.


이 답변을 작성하는 시점에서 C# 8.0은 아직 공식적으로 출시되지 않았습니다.
C# 8.x 및 .NetCore 3.x는 이제 Visual Studio 2019 이상에서 사용할 수 있습니다.

static byte[] SliceMe(byte[] source, int length)
{
    byte[] destfoo = new byte[length];
    Array.Copy(source, 0, destfoo, 0, length);
    return destfoo;
}

//

var myslice = SliceMe(sourcearray,41);

C# 7.2에서는 을 사용할 수 있습니다.새로운 시스템의 이점은 데이터를 복사할 필요가 없다는 것입니다.

당신이 필요로 하는 방법은Slice:

Span<byte> slice = foo.Slice(0, 40);

현재 많은 방법이 지원됩니다.Span그리고.IReadOnlySpan따라서 이 새로운 유형을 사용하는 것은 매우 간단합니다.

기록할 때 주의할 점은Span<T>.NET의 최신 버전(4.7.1)에는 아직 유형이 정의되어 있지 않으므로 이를 사용하려면 시스템을 설치해야 합니다.NuGet의 메모리 패키지입니다.

C# 8(2019년 이후)은 훨씬 더 쉽게 슬라이스를 달성할 수 있는 범위를 지원합니다(JS 구문과 유사).

var array = new int[] { 1, 2, 3, 4, 5 };
var slice1 = array[2..^3];    // array[new Range(2, new Index(3, fromEnd: true))]
var slice2 = array[..^3];     // array[Range.EndAt(new Index(3, fromEnd: true))]
var slice3 = array[2..];      // array[Range.StartAt(2)]
var slice4 = array[..];       // array[Range.All]

잘 알려진 LINQ 기능 대신 범위를 사용할 수 있습니다.(), 테이크(), 카운트()건너뜁니다.

제가 여기서 언급하지 않은 또 다른 가능성은 버퍼입니다.BlockCopy()가 Array보다 약간 빠릅니다.복사()는 기본 배열(예: 짧은[])에서 바이트 배열로 즉시 변환할 수 있는 추가적인 이점이 있습니다. 이는 소켓을 통해 전송해야 하는 숫자 배열이 있을 때 유용합니다.

네가 원한다면IEnumerable<byte> 그냥 .

IEnumerable<byte> data = foo.Take(x);

슬라이스를 새 배열로 반환하는 간단한 확장 방법은 다음과 같습니다.

public static T[] Slice<T>(this T[] arr, uint indexFrom, uint indexTo) {
    if (indexFrom > indexTo) {
        throw new ArgumentOutOfRangeException("indexFrom is bigger than indexTo!");
    }

    uint length = indexTo - indexFrom;
    T[] result = new T[length];
    Array.Copy(arr, indexFrom, result, 0, length);

    return result;
}

그런 다음 다음과 같이 사용할 수 있습니다.

byte[] slice = foo.Slice(0, 40);

LINQ 또는 기타 확장을 추가하지 않으려면 다음을 수행합니다.

float[] subArray = new List<float>(myArray).GetRange(0, 8).ToArray();
byte[] foo = new byte[4096]; 

byte[] bar = foo.Take(40).ToArray();

바이트 배열의 경우 시스템.Buffer.BlockCopy는 최상의 성능을 제공합니다.

이 (테스트되지 않은) 코드 조각에서와 같이 원래 배열(IList) 주위에 래퍼를 사용할 수 있습니다.

public class SubList<T> : IList<T>
{
    #region Fields

    private readonly int startIndex;
    private readonly int endIndex;
    private readonly int count;
    private readonly IList<T> source;

    #endregion

    public SubList(IList<T> source, int startIndex, int count)
    {
        this.source = source;
        this.startIndex = startIndex;
        this.count = count;
        this.endIndex = this.startIndex + this.count - 1;
    }

    #region IList<T> Members

    public int IndexOf(T item)
    {
        if (item != null)
        {
            for (int i = this.startIndex; i <= this.endIndex; i++)
            {
                if (item.Equals(this.source[i]))
                    return i;
            }
        }
        else
        {
            for (int i = this.startIndex; i <= this.endIndex; i++)
            {
                if (this.source[i] == null)
                    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 >= 0 && index < this.count)
                return this.source[index + this.startIndex];
            else
                throw new IndexOutOfRangeException("index");
        }
        set
        {
            if (index >= 0 && index < this.count)
                this.source[index + this.startIndex] = value;
            else
                throw new IndexOutOfRangeException("index");
        }
    }

    #endregion

    #region ICollection<T> Members

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

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

    public bool Contains(T item)
    {
        return this.IndexOf(item) >= 0;
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        for (int i=0; i<this.count; i++)
        {
            array[arrayIndex + i] = this.source[i + this.startIndex];
        }
    }

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

    public bool IsReadOnly
    {
        get { return true; }
    }

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

    #endregion

    #region IEnumerable<T> Members

    public IEnumerator<T> GetEnumerator()
    {
        for (int i = this.startIndex; i < this.endIndex; i++)
        {
            yield return this.source[i];
        }
    }

    #endregion

    #region IEnumerable Members

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

    #endregion
}

Take 확장 메서드를 사용할 수 있습니다.

var array = new byte[] {1, 2, 3, 4};
var firstTwoItems = array.Take(2);

이는 다음과 같은 솔루션일 수 있습니다.

var result = foo.Slice(40, int.MaxValue);

그런 다음 첫 번째 IEnumberablefoo의 첫 번째 40바이트를 포함하는 IEnumberable<byte>가 생성되고 두 번째 IEnumberable<byte>가 나머지를 유지합니다.

저는 래퍼 클래스를 썼고, 전체 반복은 게으릅니다. 도움이 될 수 있기를 바랍니다.

public static class CollectionSlicer
{
    public static IEnumerable<IEnumerable<T>> Slice<T>(this IEnumerable<T> source, params int[] steps)
    {
        if (!steps.Any(step => step != 0))
        {
            throw new InvalidOperationException("Can't slice a collection with step length 0.");
        }
        return new Slicer<T>(source.GetEnumerator(), steps).Slice();
    }
}

public sealed class Slicer<T>
{
    public Slicer(IEnumerator<T> iterator, int[] steps)
    {
        _iterator = iterator;
        _steps = steps;
        _index = 0;
        _currentStep = 0;
        _isHasNext = true;
    }

    public int Index
    {
        get { return _index; }
    }

    public IEnumerable<IEnumerable<T>> Slice()
    {
        var length = _steps.Length;
        var index = 1;
        var step = 0;

        for (var i = 0; _isHasNext; ++i)
        {
            if (i < length)
            {
                step = _steps[i];
                _currentStep = step - 1;
            }

            while (_index < index && _isHasNext)
            {
                _isHasNext = MoveNext();
            }

            if (_isHasNext)
            {
                yield return SliceInternal();
                index += step;
            }
        }
    }

    private IEnumerable<T> SliceInternal()
    {
        if (_currentStep == -1) yield break;
        yield return _iterator.Current;

        for (var count = 0; count < _currentStep && _isHasNext; ++count)
        {
            _isHasNext = MoveNext();

            if (_isHasNext)
            {
                yield return _iterator.Current;
            }
        }
    }

    private bool MoveNext()
    {
        ++_index;
        return _iterator.MoveNext();
    }

    private readonly IEnumerator<T> _iterator;
    private readonly int[] _steps;
    private volatile bool _isHasNext;
    private volatile int _currentStep;
    private volatile int _index;
}

C#이 Range 의미론을 지원하지 않는다고 생각합니다.그러나 다음과 같은 확장 방법을 작성할 수 있습니다.

public static IEnumerator<Byte> Range(this byte[] array, int start, int end);

하지만 다른 사람들이 말했듯이, 만약 당신이 시작 지수를 설정할 필요가 없다면 그때.Take당신이 필요한 것은 전부입니다.

여기 제네릭을 사용하고 PHP 함수 array_slice처럼 동작하는 확장 함수가 있습니다.음의 오프셋 및 길이가 허용됩니다.

public static class Extensions
{
    public static T[] Slice<T>(this T[] arr, int offset, int length)
    {
        int start, end;

        // Determine start index, handling negative offset.
        if (offset < 0)
            start = arr.Length + offset;
        else
            start = offset;

        // Clamp start index to the bounds of the input array.
        if (start < 0)
            start = 0;
        else if (start > arr.Length)
            start = arr.Length;

        // Determine end index, handling negative length.
        if (length < 0)
            end = arr.Length + length;
        else
            end = start + length;

        // Clamp end index to the bounds of the input array.
        if (end < 0)
            end = 0;
        if (end > arr.Length)
            end = arr.Length;

        // Get the array slice.
        int len = end - start;
        T[] result = new T[len];
        for (int i = 0; i < len; i++)
        {
            result[i] = arr[start + i];
        }
        return result;
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace data_seniens
{
    class Program
    {
        static void Main(string[] args)
        {
            //new list
            float [] x=new float[]{11.25f,18.0f,20.0f,10.75f,9.50f, 11.25f, 18.0f, 20.0f, 10.75f, 9.50f };

            //variable
            float eat_sleep_area=x[1]+x[3];
            //print
            foreach (var VARIABLE in x)
            {
                if (VARIABLE < x[7])
                {
                    Console.WriteLine(VARIABLE);
                }
            }



            //keep app run
        Console.ReadLine();
        }
    }
}

언급URL : https://stackoverflow.com/questions/406485/array-slices-in-c-sharp

반응형