2010-03-05 2 views
2

여러 가지 순위를 매길 필요가있는 목록의 개체가 목록에 있습니다. 현재 코드는 각 열을 개별적으로 주소 지정해야하기 때문에 다루기가 쉽지 않습니다. 예 :순위 지정 데이터 처리 C# 및 LINQ

public class Data 
{ 
    public int AValue { get; set; } 
    public int ARanking { get; set; } 
    public int BValue { get; set; } 
    public int BRanking { get; set; } 
    public int CValue { get; set; } 
    public int CRanking { get; set; } 
} 

public class Container 
{ 
    public List<Data> RankingData { get; set; } 

    public void RankData() 
    { 
     int count = 1; 

     foreach (Data item in RankingData.OrderBy(d => d.AValue)) 
     { 
      item.ARanking = count; 
      count++; 
     } 

     count = 1; 

     foreach (Data item in RankingData.OrderBy(d => d.BValue)) 
     { 
      item.BRanking = count; 
      count++; 
     } 

     count = 1; 

     foreach (Data item in RankingData.OrderBy(d => d.CValue)) 
     { 
      item.CRanking = count; 
      count++; 
     } 
    } 
} 

의 I는 해결하기 위해 노력하고 문제를 내가 거의 같은 것을 쓰고 싶은 것입니다 : 그래서

public void RankData<V, R>() 
{ 
    int count = 1; 

    foreach(Data item in RankingData.OrderBy(V)) 
    { 
     item.R = count; 
     count++; 
    } 
} 

을 그 나는 타이 브레이크를 처리 (예를 들어, 순위 로직을 변경해야으로 규칙) 규칙을 일치시키기 위해 코드를 20 번 복사하는 대신 코드를 한 번 씁니다. 내가 뭘 놓치고 있니? 내가 있는지 여부를 제어 할 수 있도록 스위치를 추가했다

public static class RankingExtension 
{ 
    public static void SetRanking<TKey>(this List<Data> dataSet, bool Ascending, Func<Data, TKey> getOrderBy, Action<Data, int> setRank) 
     where TKey : IComparable 
    { 
     var ordered = (Ascending) ? dataSet.OrderBy(getOrderBy) : dataSet.OrderByDescending(getOrderBy); 

     int i = 1; 
     foreach (Data item in ordered) 
     { 
      setRank(item, i); 
      i++; 
     } 
    } 
} 

이 도심 Tanzelax의 솔루션을 사용하여

UPDATE

내가 생각 해낸 확장 클래스입니다 필드가 오름차순으로 정렬 되었습니까? 이 같은 테스트를하지

List<Data> test = new List<Data>(); 
    test.Add(new Data { AValue = 25, BValue = 1.25, CValue = 99.99 }); 
    test.Add(new Data { AValue = 89, BValue = 2.10, CValue = 1.01 }); 
    test.Add(new Data { AValue = 10, BValue = 6, CValue = 45.45 }); 
    test.Add(new Data { AValue = 15, BValue = 2.33, CValue = 2.99 }); 
    test.Add(new Data { AValue = 90, BValue = 5.43, CValue = 27.89 }); 

    test.SetRanking(false, d => d.AValue, (d, i) => d.ARank = i); 
    test.SetRanking(false, d => d.BValue, (d, i) => d.BRank = i); 
    test.SetRanking(true, d => d.CValue, (d, i) => d.CRank = i); 

답변

1

,하지만 뭔가 : 그리고 내 테스트 시나리오에 적절한 출력을 생성 순위 키를 반환하는 Func<Data,K>에서

void SetRanking(this List<Data> dataSet, Func<Data,int> getOrderBy, Action<Data,int> setRank) 
{ 
    var ordered = dataSet.OrderBy(getOrderBy).ToArray(); 

    int i = i; 
    foreach (Data item in ordered) 
    { 
     setRank(item, i); 
     i++; 
    } 
} 

RankingData.SetRanking(d => d.AValue, (d,i) => d.ARanking = i); 
RankingData.SetRanking(d => d.BValue, (d,i) => d.BRanking = i); 
RankingData.SetRanking(d => d.CValue, (d,i) => d.CRanking = i); 
+0

코드가 없지만 가까운 거리에 있습니다. 나는 나의 수정을 조금 올릴 것이다. – thaBadDawg

+0

@thaBadDawg : 기꺼이 도와 드릴 수 있습니다. :) 또한 데이터 및 기타 등등 밖으로 제네릭 수 있습니다. 또한, 오름차순 bool을 전달하는 대신, 많은 사람들이 그 접근 방식에 반대 할 것이라고 확신하지만 음수 CValue를 orderBy lambda로 전달할 수 있습니다. – Tanzelax

0

패스. K는 IComparable을 구현해야합니다.

public static void Rank<K>(IEnumerable<Data> source, Func<Data,K> rankBy) where K : IComparable 
{ 
    int count = 1; 
    foreach (var item in source.OrderBy(rankBy)) 
    { 
     item.R = count; 
     ++count; 
    } 
} 
1

이것은 Tanzelax의 대답과 유사하지만 일반적인 확장 방법입니다.

public static void RankData<TSource, TKey>(
    this IEnumerable<TSource> source, 
    Func<TSource, TKey> keySelector, 
    Action<TSource, int> rankSetter 
) 
{ 
    int count = 1; 
    foreach (var item in source.OrderBy(keySelector)) 
    { 
     rankSetter(item, count); 
     ++count; 
    } 
} 

Tanzelax의 대답과 비슷하게 호출됩니다.

RankingData.RankData(d => d.AValue, (d,i) => d.ARanking = i);