KeiStory

반응형

Sorting 된 목록에서 데이터 변경점 찾아내기

 

데이터 목록이 있을때 특정 컬럼으로 정렬을 하고나서 변경점을 찾아내는 방법을 알아봅니다.

저는 변경점을 찾아내서 그리드에서 구분선을 그을 필요가 있어 사용했습니다.

데이터가 List<dynamic> 인 경우 처리 방법입니다.

Util.cs

using System.Dynamic;

namespace ConsoleApp5
{
    public static class Util
    {
        public static object GetPropertyValue(dynamic obj, string propertyName)
        {
            if (obj is ExpandoObject)
            {
                var dict = (IDictionary<string, object>)obj;
                return dict.ContainsKey(propertyName) ? dict[propertyName] : null;
            }

            var prop = obj.GetType().GetProperty(propertyName);
            return prop?.GetValue(obj, null);
        }
    }
}

 

Program.cs

using System.Dynamic;

namespace ConsoleApp5
{
    public static class DynamicListExtensions
    {
        public static List<int> GetChangeIndicesByProperty(this List<dynamic> source, string propertyName)
        {
            // 정렬
            var sorted = source.OrderBy(x => Util.GetPropertyValue(x, propertyName)).ToList();

            foreach (var itemIndex in sorted.Select((item, index) => new { Item = item, Index = index }))
            {
                Console.WriteLine($"index {itemIndex.Index}, {itemIndex.Item.Category}");
            }

            // 변경 지점 찾기
            return sorted
                .Select((item, index) => new { Value = Util.GetPropertyValue(item, propertyName), Index = index })
                .Where(x => x.Index == 0 || !object.Equals(
                    x.Value, Util.GetPropertyValue(sorted[x.Index - 1], propertyName)))
                .Select(x => x.Index)
                .ToList();
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            dynamic item1 = new ExpandoObject();
            item1.Category = "B";
            item1.Name = "Banana";

            dynamic item2 = new ExpandoObject();
            item2.Category = "A";
            item2.Name = "Apple";

            dynamic item3 = new ExpandoObject();
            item3.Category = "A";
            item3.Name = "Avocado";

            dynamic item4 = new ExpandoObject();
            item4.Category = "C";
            item4.Name = "Cherry";

            dynamic item5 = new ExpandoObject();
            item5.Category = "B";
            item5.Name = "Blueberry";

            List<dynamic> items = new List<dynamic> { item1, item2, item3, item4, item5 };

            string sortBy = "Category";
            var changeIndices = items.GetChangeIndicesByProperty(sortBy);

            var sorted = items.OrderBy(x => Util.GetPropertyValue(x, sortBy)).ToList();

            foreach (var index in changeIndices)
            {
                Console.WriteLine($"Change at index {index}, {sortBy}: {Util.GetPropertyValue(sorted[index], sortBy)}");
            }
        }
    }
}

위 코드를 보면 알수 있듯이 Category 컬럼 기준으로 정렬을 한 후 해당 컬럼의 데이터가 변경되는 시점을 뽑아줍니다.

위 결과는 아래와 같습니다.

0 번째는 무조건 나와서 제거 하고 사용하면 됩니다.

 

아래처럼 코딩하면 한꺼번에 정렬과 변경점 index 를 한꺼번에 처리가 됩니다.

public static List<(int Index, object Value)> GetChangePoints(this List<dynamic> source, string propertyName)
{
    return source
        .Select(item => new { Item = item, Value = Util.GetPropertyValue(item, propertyName) })
        .OrderBy(x => x.Value)
        .Select((x, index) => new { x.Item, x.Value, Index = index })
        .Where(x =>
            x.Index > 0 && !object.Equals(
                x.Value,
                GetProp(source.OrderBy(y => Util.GetPropertyValue(y, propertyName)).ElementAt(x.Index - 1), propertyName)))
        .Select(x => (x.Index, x.Value))
        .ToList();
}

 

반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band