C#

C#] Indices(har operator ^), Range(range operator ..)

Fastlane 2024. 4. 26. 15:58
728x90
반응형

sequence의 elements 중 하나 또는 범위에 어떻게 접근할 수 있는지 살펴보자. 

Indices

sequence의 index를 나타낸다. C# 8.0부터 ^ operator로 index를 지정할 수 있다. constructor Index는 2개의 paramter로 구성되어 있다. 

public Index (int value, bool fromEnd = false);

index는 0보다 크거나 같아야 하며, fromEnd는 optional이다. 

 

Index는 아래와 같이 사용할 수 있다. 

public class IndexExamples
{
    public static string GetFirst(string[] names)
    {
        var index = new Index(0);

        return names[index];
    }

    public static string GetLastMethod1(string[] names)
    {
        var index = new Index(1, true);

        return names[index];
    }
}

GetFirst는 array의 첫번째 element를 반환하고, GetLastMethod1은 array의 마지막 element를 반환한다. 

코드는 정상 동작하지만, 우리는 더 심플하게 수정할 수 있다. 

public static string GetLastMethod2(string[] names)
{
   return names[^1];
}

public static string GetSecondLast(string[] names)
{
    return names[^2];
}

 

GetLastMethod1, GetLastMethod2 모두 동일한 결과가 있지만, GetLastMethod2의 구분이 더 간결하다. 

 

  • names[^1] 은 names[names.Length - 1]과 동일하다. 

Ranges

Ranges는 ..operator를 사용하여 sequence의 부분의 표현하는 간결한 방식이다. range operator는 slice의 시작과 끝을 명시한다. x..y를 예로 들어보자. 

  • x는 시작 index
  • y는 마지막 index
  • x, y는 선택적 값이다. 
  • range operator(..)는 시작 index(x)를 포함하고, 마지막 index(y)는 제외한다. 

Range class의 constructor를 살펴보자. 

public Range(Index start, Index end);

 

RangeExamples class를 만들고 range operator(..)를 다양하게 사용해보자. 

public class RangeExamples
{
    public static string[] GetAll(string[] arr)
    {
        return arr[..];
    }

    public static string[] GetFirstTwoElements(string[] arr) 
    {
        var start = new Index(0);
        var end = new Index(2);
        var range = new Range(start, end);

        return arr[range];
    }

    public static string[] GetFirstThreeElements(string[] arr) 
    {
        return arr[..3];
    }

    public static string[] GetLastThreeElements(string[] arr) 
    {
        return arr[^3..];
    }

    public static string[] GetThreeElementsFromMiddle(string[] arr) 
    {
        return arr[3..6];
    }
}

사용 제한

List<T>와 같은 내장타입이나 custom type과는 Range, Index를 사용할 수 없다. 하지만, 지원하도록 수정 가능하다. NameList class를 만들고, Index, Range를 지원하도록 수정해보자. 

public class NameList : IEnumerable<string>
{
    private List<string> _names;

    public NameList()
    {
        _names = new List<string>();
    }

    public IEnumerator<string> GetEnumerator()
    {
        return _names.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)_names).GetEnumerator();
    }
    
    public void Add(string name) => _names.Add(name);
}

NameList class에 대해서 index를 사용할 수 없다. indexable하게 수정하려면, object를 countable하게 바꿔야 한다. Count와 Length property를 추가한다. 

Range를 사용할 수 있도록 Slice method를 추가한다. 

public class NameList : IEnumerable<string>
{
    private List<string> _names;

    public NameList()
    {
        _names = new List<string>();
    }

    public string this[int index] => _names[index];

    public int Count => _names.Count;

    public IEnumerator<string> GetEnumerator()
    {
        return _names.GetEnumerator();
    }

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

    public void Add(string name) => _names.Add(name);

    public List<string> Slice(int start, int length)
        => _names
              .Skip(start)
              .Take(length)
              .ToList();

}

이제 Index와 Range를 사용할 수 있다. 

public class NameListExamples
{
    public static List<string> GetAll(NameList names)
    {
        return names[..];
    }

    public static List<string> GetFirstTwoElements(NameList names)
    {
        var start = new Index(0);
        var end = new Index(2);
        var range = new Range(start, end);
        return names[range];
    }

    public static List<string> GetFirstThreeElements(NameList names)
    {
        return names[..3];
    }

    public static List<string> GetLastThreeElements(NameList names)
    {
        return names[^3..];
    }

    public static List<string> GetThreeElementsFromMiddle(NameList names)
    {
        return names[3..6];
    }

    public static string GetLastElement(NameList names)
    {
        return names[^1];
    }
}

NameList class처럼 range, indice는 필요조건을 충족하는 어떤 class와도 사용 가능하다. 

 

결론

C#에서의 Index, Range를 살펴보았다. 그리고, custom type에서 Index, Range를 지원하도록 수정해보았다. 

728x90
반응형