NGMsoftware

NGMsoftware
로그인 회원가입
  • 매뉴얼
  • 학습
  • 매뉴얼

    학습


    C# C# .NET 매크로 프로그램 만들기. (배열 정렬하기 1부)

    페이지 정보

    본문

    안녕하세요. 엔지엠소프트웨어입니다. 오늘은 배열 정렬 기능을 개발 해볼께요. 앞서, 배열을 처리하는 방법을 배웠기 때문에 자잘한 로직 설명은 건너뛰고 정렬 기능에 대해서만 설명하면서 코딩하면 될듯합니다. 우선, 배열 정렬 액션을 하나 추가 해줍니다. 모델명은 ArraySortModel입니다. 이름만 봐도 아~ 이녀석이 뭘 하는구나하고 유추할 수 있습니다. 괜찮은 이름이죠?

    V0af1Hy.png

     

     

    배열을 정렬하기 위해서는 아래와 같은 속성들이 필요합니다. 중요한 몇가지만 알고 넘어가면 될거 같아요.

    public class ArraySortModel : BaseModel
    {
        [NonSerialized]
        private string[]? _datas;
    
        [LocalizedCategory("Data")]
        [LocalizedDisplayName("Result")]
        [LocalizedDescription("Result")]
        [Browsable(true)]
        [DefaultValue(null)]
        public string[]? Result { get; set; }
    
        [LocalizedCategory("Array")]
        [LocalizedDisplayName("RepeatData")]
        [LocalizedDescription("RepeatData")]
        [Browsable(true)]
        [DefaultValue(null)]
        public string[]? ArrayData { get { return _datas; } set { _datas = value; } }
    
        [LocalizedCategory("Array")]
        [LocalizedDisplayName("ArraySortOption")]
        [LocalizedDescription("ArraySortOption")]
        [Browsable(true)]
        [DefaultValue(typeof(Ai.Definition.Sort), "None")]
        public Ai.Definition.Sort ArraySortOption { get; set; } = Definition.Sort.None;
    
        [LocalizedCategory("Array")]
        [LocalizedDisplayName("DataType")]
        [LocalizedDescription("DataType")]
        [Browsable(true)]
        [DefaultValue(typeof(Ai.Definition.DataType), "Text")]
        public Ai.Definition.DataType DataType { get; set; } = Definition.DataType.Text;
    
        [LocalizedCategory("Array")]
        [LocalizedDisplayName("SortOption")]
        [LocalizedDescription("SortOption")]
        [Browsable(true)]
        [DefaultValue(typeof(Ai.Definition.DataType), "X")]
        public Ai.Definition.SortOption SortOption { get; set; } = Definition.SortOption.X;

     

    ArraySortOption은 기본값이 None입니다. 아무것도 처리하지 않는데요. 어떻게 배열의 값을 처리할지는 사용자가 선택해야 합니다.

    [LocalizedCategory("Array")]
    [LocalizedDisplayName("ArraySortOption")]
    [LocalizedDescription("ArraySortOption")]
    [Browsable(true)]
    [DefaultValue(typeof(Ai.Definition.Sort), "None")]
    public Ai.Definition.Sort ArraySortOption { get; set; } = Definition.Sort.None;

     

    정렬 기준은 아래와 같습니다. 오름차순, 내림차순, 역순, 특정 위치에서 가까운 순서와 먼 순서 그리고, 셔플입니다.

    public enum Sort
    {
        None = 0,
        Ascending = 1,
        Descending = 2,
        Reverse = 3,
        Far = 4,
        Near = 5,
        Shuffle = 6
    }

     

    Far와 Near는 데이터 형식이 좌표를 포함하고 있을 때 사용하는 옵션인데요. 특정 숫자나 문자에도 적용할 수 있을듯 합니다. 이 부분은 나중에 추가 개발을 통해서 자세하게 알아볼께요. 배열 정렬하기 2부 내용도 기대해주시고, 오늘은 오름차순과 내림차순, 역순을 개발할거예요.

     

    데이터 형식은 아래와 같은데요. 테이터 형식에 따라서 처리 로직이 달라져야 합니다. 전부다 문자로 변환해서 처리해도 되긴 하지만, 이렇게하면 의도하지 않은 방식으로 정렬될 수 있습니다. 가령, 좌표의 경우 나는 Y좌표를 기준으로 위에서 아래로 정렬하고 싶은데 X 값이 가장 앞에 있어서 X 순서로 정렬되는 경우를 생각 해볼 수 있을거 같아요.

    public enum DataType
    {
        Text = 0,
        Number = 1,
        Point = 2,
        Size = 3,
        Rectangle = 4
    }

     

    위 내용에 연장선으로 데이터가 좌표, 크기, 사각형인 경우 아래와 같이 추가 옵션을 제공해야 합니다.

    [LocalizedCategory("Array")]
    [LocalizedDisplayName("SortOption")]
    [LocalizedDescription("SortOption")]
    [Browsable(true)]
    [DefaultValue(typeof(Ai.Definition.DataType), "X")]
    public Ai.Definition.SortOption SortOption { get; set; } = Definition.SortOption.X;

     

    SortOption은 아래와 같이 많은 속성들이 있습니다. 좌표가 사용하는 것과 크기가 사용하는게 나눠져 있습니다. 사각형은 둘다 가지고 있으므로 모두 사용해야 합니다. 참고로, XY와 XnY가 있는데요. 이 둘의 차이점은 정렬 방법입니다. 정렬을 내림차순으로 선택했을 때 XY는 X 기준으로 내림차순하고, 그 다음에 Y도 내림차순으로 정렬해줍니다. X 좌표 값이 같을수도 있으니까요. 이런 경우 Y 좌표 설정 값으로 한번 더 정렬합니다. XnY는 X 좌표로 우선 정렬하고, 같은 값인 경우에는 Y 좌표는 오름차순으로 정렬할 때 사용하는 옵션입니다.

    public enum SortOption
    {
        X = 0,
        Y = 1,
        XY = 2,
        XnY = 3,
        YX = 4,
        YnX = 5,
        W = 6,
        H = 7,
        WH = 8,
        WnH = 9,
        HW = 10,
        HnW = 11
    }

     

    데이터 형식에 따라서 switch ~ case로 하나씩 구현해줘야 합니다.

    switch (DataType)
    {
        case Definition.DataType.Text:
            var arrText = ArrayData.Cast<object>().Select(x => x.ToString()).ToArray();
    
            switch (ArraySortOption)
            {
                case Definition.Sort.Ascending:
                    Result = arrText.OrderByNatural(o => o).ToArray();
                    break;
                case Definition.Sort.Descending:
                    Result = arrText.OrderByDescendingNatural(o => o).ToArray();
                    break;
                case Definition.Sort.Reverse:
                    Result = arrText.Reverse().ToArray();
                    break;
                case Definition.Sort.Shuffle:
                    Result = arrText.Shuffle().ToArray();
                    break;
                case Definition.Sort.Far:
                    break;
                case Definition.Sort.Near:
                    break;
            }

     

    여기서 핵심 내용이 하나 나옵니다. 우리가 일반적으로 정려할 때 아래 내용을 고려해봐야 합니다. { "a10", "a7", "a" } 배열이 있으면 어떻게 정렬이 될까요? 아마도 예상으로는 a, a7, a10처럼 될거라고 생각할거 같은데요. 실제로는 문자열이기 때문에 a, a10, a7과 같이 정렬됩니다. 이렇게 되는 이유는 문자를 앞에서부터 하나씩 비교하면서 정렬하기 때문입니다. 그래서, a 다음에 1이 나오는 a10이 a7보다 우선됩니다. OrderBy가 아닌 Sort를 사용해도 결과는 동일합니다.

    YjfWy4F.png

     

     

    하지만, 윈도우에서 정렬은 어떨까요? a, a7, a10과 같이 정렬되는데요. 이게 자연스럽죠?

     

     

    그래서, 프로그래밍에서 윈도우처럼 자연스럽게 정렬하기 위한 다양한 방법들이 존재합니다. 윈도우의 정렬 기능을 빼와서 적용시킬수도 있는데요. 이건, 윈도우 환경이 아닌 리눅스나 유닉스와 같은 곳에서는 어차피 사용하지 못하고, 로직을 만들어야 합니다. 그래서, 보통 아래와 같이 사용합니다.

    public static IEnumerable<T> OrderByNatural<T>(IEnumerable<T> items, Func<T, object> selector, StringComparer? stringComparer = null)
    {
        var regex = new Regex(@"\d+", RegexOptions.Compiled);
    
        int maxDigits = items
                      .SelectMany(i => regex.Matches(selector(i).ToString()).Cast<Match>().Select(digitChunk => (int?)digitChunk.Value.Length))
                      .Max() ?? 0;
    
        return items.OrderBy(i => regex.Replace(selector(i).ToString(), match => match.Value.PadLeft(maxDigits, '0')), stringComparer ?? StringComparer.CurrentCulture);
    }

     

    이제 만들어진 정렬 기능을 사용해서 테스트를 해볼께요. 몇가지 복합적으로 사용해야 합니다. 테스트 내용은 아래 동영상을 참고하세요.

     

     

    이 글이 도움이 되셨다면~ 커피 한잔이라도 후원 부탁드립니다^^

    개발자에게 후원하기

    MGtdv7r.png

     

    추천, 구독, 홍보 꼭~ 부탁드립니다.

    여러분의 후원이 빠른 귀농을 가능하게 해줍니다~ 답답한 도시를 벗어나 귀농하고 싶은 개발자~

    감사합니다~

    • 네이버 공유하기
    • 페이스북 공유하기
    • 트위터 공유하기
    • 카카오스토리 공유하기
    추천0 비추천0

    댓글목록

    등록된 댓글이 없습니다.